static void parse_exif_rational_tag (GstExifReader * exif_reader, const gchar * gst_tag, guint32 count, guint32 offset, gdouble multiplier) { GstByteReader data_reader; guint32 real_offset; guint32 frac_n = 0; guint32 frac_d = 1; gdouble value; if (count > 1) { GST_WARNING ("Rationals with multiple entries are not supported"); } if (offset < exif_reader->base_offset) { GST_WARNING ("Offset is smaller (%u) than base offset (%u)", offset, exif_reader->base_offset); return; } real_offset = offset - exif_reader->base_offset; if (real_offset >= GST_BUFFER_SIZE (exif_reader->buffer)) { GST_WARNING ("Invalid offset %u for buffer of size %u, not adding tag %s", real_offset, GST_BUFFER_SIZE (exif_reader->buffer), gst_tag); return; } gst_byte_reader_init_from_buffer (&data_reader, exif_reader->buffer); if (!gst_byte_reader_set_pos (&data_reader, real_offset)) goto reader_fail; if (exif_reader->byte_order == G_LITTLE_ENDIAN) { if (!gst_byte_reader_get_uint32_le (&data_reader, &frac_n) || !gst_byte_reader_get_uint32_le (&data_reader, &frac_d)) goto reader_fail; } else { if (!gst_byte_reader_get_uint32_be (&data_reader, &frac_n) || !gst_byte_reader_get_uint32_be (&data_reader, &frac_d)) goto reader_fail; } GST_DEBUG ("Read fraction for tag %s: %u/%u", gst_tag, frac_n, frac_d); gst_util_fraction_to_double (frac_n, frac_d, &value); value *= multiplier; GST_DEBUG ("Adding %s tag: %lf", gst_tag, value); gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE, gst_tag, value, NULL); return; reader_fail: GST_WARNING ("Failed to read from byte reader. (Buffer too short?)"); }
static gboolean parse_exif_tag_header (GstByteReader * reader, gint byte_order, GstExifTagData * _tagdata) { g_assert (_tagdata); /* read the fields */ if (byte_order == G_LITTLE_ENDIAN) { if (!gst_byte_reader_get_uint16_le (reader, &_tagdata->tag) || !gst_byte_reader_get_uint16_le (reader, &_tagdata->tag_type) || !gst_byte_reader_get_uint32_le (reader, &_tagdata->count) || !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) { return FALSE; } _tagdata->offset = GST_READ_UINT32_LE (_tagdata->offset_as_data); } else { if (!gst_byte_reader_get_uint16_be (reader, &_tagdata->tag) || !gst_byte_reader_get_uint16_be (reader, &_tagdata->tag_type) || !gst_byte_reader_get_uint32_be (reader, &_tagdata->count) || !gst_byte_reader_get_data (reader, 4, &_tagdata->offset_as_data)) { return FALSE; } _tagdata->offset = GST_READ_UINT32_BE (_tagdata->offset_as_data); } return TRUE; }
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; }
/** * gst_tag_list_from_exif_buffer_with_tiff_header: * @buffer: The exif buffer * * Parses the exif tags starting with a tiff header structure. * * Returns: The taglist * * Since: 0.10.30 */ GstTagList * gst_tag_list_from_exif_buffer_with_tiff_header (const GstBuffer * buffer) { GstByteReader reader; guint16 fortytwo = 42; guint16 endianness = 0; guint32 offset; GstTagList *taglist = NULL; GstBuffer *subbuffer; GST_LOG ("Parsing exif tags with tiff header of size %u", GST_BUFFER_SIZE (buffer)); gst_byte_reader_init_from_buffer (&reader, buffer); GST_LOG ("Parsing the tiff header"); if (!gst_byte_reader_get_uint16_be (&reader, &endianness)) { goto byte_reader_fail; } if (endianness == TIFF_LITTLE_ENDIAN) { if (!gst_byte_reader_get_uint16_le (&reader, &fortytwo) || !gst_byte_reader_get_uint32_le (&reader, &offset)) goto byte_reader_fail; } else if (endianness == TIFF_BIG_ENDIAN) { if (!gst_byte_reader_get_uint16_be (&reader, &fortytwo) || !gst_byte_reader_get_uint32_be (&reader, &offset)) goto byte_reader_fail; } else { GST_WARNING ("Invalid endianness number %u", endianness); return NULL; } if (fortytwo != 42) { GST_WARNING ("Invalid magic number %u, should be 42", fortytwo); return NULL; } subbuffer = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buffer) - (TIFF_HEADER_SIZE - 2)); memcpy (GST_BUFFER_DATA (subbuffer), GST_BUFFER_DATA (buffer) + TIFF_HEADER_SIZE, GST_BUFFER_SIZE (buffer) - TIFF_HEADER_SIZE); taglist = gst_tag_list_from_exif_buffer (subbuffer, endianness == TIFF_LITTLE_ENDIAN ? G_LITTLE_ENDIAN : G_BIG_ENDIAN, 8); gst_buffer_unref (subbuffer); return taglist; byte_reader_fail: { GST_WARNING ("Failed to read values from buffer"); return NULL; } }
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_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; }
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); }
static void gst_exif_tag_rewrite_offsets (GstExifWriter * writer, guint32 base_offset) { guint32 offset; GST_LOG ("Rewriting tag entries offsets"); offset = gst_byte_writer_get_size (&writer->tagwriter); while (gst_byte_writer_get_pos (&writer->tagwriter) < gst_byte_writer_get_size (&writer->tagwriter)) { guint16 type = 0; guint32 cur_offset = 0; GstByteReader *reader; gint byte_size = 0; guint32 count = 0; guint16 tag_id = 0; reader = (GstByteReader *) & writer->tagwriter; /* read the type */ if (writer->byte_order == G_LITTLE_ENDIAN) { if (!gst_byte_reader_get_uint16_le (reader, &tag_id)) break; if (!gst_byte_reader_get_uint16_le (reader, &type)) break; if (!gst_byte_reader_get_uint32_le (reader, &count)) break; } else { if (!gst_byte_reader_get_uint16_be (reader, &tag_id)) break; if (!gst_byte_reader_get_uint16_be (reader, &type)) break; if (!gst_byte_reader_get_uint32_be (reader, &count)) break; } switch (type) { case EXIF_TYPE_BYTE: case EXIF_TYPE_ASCII: case EXIF_TYPE_UNDEFINED: byte_size = count; break; case EXIF_TYPE_SHORT: byte_size = count * 2; /* 2 bytes */ break; case EXIF_TYPE_LONG: case EXIF_TYPE_SLONG: byte_size = count * 4; /* 4 bytes */ break; case EXIF_TYPE_RATIONAL: case EXIF_TYPE_SRATIONAL: byte_size = count * 8; /* 8 bytes */ break; default: g_assert_not_reached (); break; } /* adjust the offset if needed */ if (byte_size > 4 || tag_id == EXIF_GPS_IFD_TAG) { if (writer->byte_order == G_LITTLE_ENDIAN) { if (gst_byte_reader_peek_uint32_le (reader, &cur_offset)) { gst_byte_writer_put_uint32_le (&writer->tagwriter, cur_offset + offset + base_offset); } } else { if (gst_byte_reader_peek_uint32_be (reader, &cur_offset)) { gst_byte_writer_put_uint32_be (&writer->tagwriter, cur_offset + offset + base_offset); } } GST_DEBUG ("Rewriting tag offset from %u to (%u + %u + %u) %u", cur_offset, cur_offset, offset, base_offset, cur_offset + offset + base_offset); } else { gst_byte_reader_skip (reader, 4); GST_DEBUG ("No need to rewrite tag offset"); } } }
static gint deserialize_geo_coordinate (GstExifReader * exif_reader, GstByteReader * reader, const GstExifTagMatch * exiftag, GstExifTagData * tagdata) { GstByteReader fractions_reader; gint multiplier; GstExifTagData next_tagdata; gint ret = 0; /* for the conversion */ guint32 degrees_n = 0; guint32 degrees_d = 1; guint32 minutes_n = 0; guint32 minutes_d = 1; guint32 seconds_n = 0; guint32 seconds_d = 1; gdouble degrees; gdouble minutes; gdouble seconds; GST_LOG ("Starting to parse %s tag in exif 0x%x", exiftag->gst_tag, exiftag->exif_tag); if (exiftag->complementary_tag != tagdata->tag) { /* First should come the 'Ref' tags */ GST_WARNING ("Tag %d is not the 'Ref' tag for latitude nor longitude", tagdata->tag); return ret; } if (tagdata->offset_as_data[0] == 'N' || tagdata->offset_as_data[0] == 'E') { multiplier = 1; } else if (tagdata->offset_as_data[0] == 'S' || tagdata->offset_as_data[0] == 'W') { multiplier = -1; } else { GST_WARNING ("Invalid LatitudeRef or LongitudeRef %c", tagdata->offset_as_data[0]); return ret; } /* now read the following tag that must be the latitude or longitude */ if (exif_reader->byte_order == G_LITTLE_ENDIAN) { if (!gst_byte_reader_peek_uint16_le (reader, &next_tagdata.tag)) goto reader_fail; } else { if (!gst_byte_reader_peek_uint16_be (reader, &next_tagdata.tag)) goto reader_fail; } if (exiftag->exif_tag != next_tagdata.tag) { GST_WARNING ("This is not a geo cordinate tag"); return ret; } /* read the remaining tag entry data */ if (!parse_exif_tag_header (reader, exif_reader->byte_order, &next_tagdata)) { ret = -1; goto reader_fail; } ret = 1; /* some checking */ if (next_tagdata.tag_type != EXIF_TYPE_RATIONAL) { GST_WARNING ("Invalid type %d for geo coordinate (latitude/longitude)", next_tagdata.tag_type); return ret; } if (next_tagdata.count != 3) { GST_WARNING ("Geo coordinate should use 3 fractions, we have %u", next_tagdata.count); return ret; } /* now parse the fractions */ gst_byte_reader_init_from_buffer (&fractions_reader, exif_reader->buffer); if (!gst_byte_reader_set_pos (&fractions_reader, next_tagdata.offset - exif_reader->base_offset)) goto reader_fail; if (exif_reader->byte_order == G_LITTLE_ENDIAN) { if (!gst_byte_reader_get_uint32_le (&fractions_reader, °rees_n) || !gst_byte_reader_get_uint32_le (&fractions_reader, °rees_d) || !gst_byte_reader_get_uint32_le (&fractions_reader, &minutes_n) || !gst_byte_reader_get_uint32_le (&fractions_reader, &minutes_d) || !gst_byte_reader_get_uint32_le (&fractions_reader, &seconds_n) || !gst_byte_reader_get_uint32_le (&fractions_reader, &seconds_d)) goto reader_fail; } else { if (!gst_byte_reader_get_uint32_be (&fractions_reader, °rees_n) || !gst_byte_reader_get_uint32_be (&fractions_reader, °rees_d) || !gst_byte_reader_get_uint32_be (&fractions_reader, &minutes_n) || !gst_byte_reader_get_uint32_be (&fractions_reader, &minutes_d) || !gst_byte_reader_get_uint32_be (&fractions_reader, &seconds_n) || !gst_byte_reader_get_uint32_be (&fractions_reader, &seconds_d)) goto reader_fail; } GST_DEBUG ("Read degrees fraction for tag %s: %u/%u %u/%u %u/%u", exiftag->gst_tag, degrees_n, degrees_d, minutes_n, minutes_d, seconds_n, seconds_d); gst_util_fraction_to_double (degrees_n, degrees_d, °rees); gst_util_fraction_to_double (minutes_n, minutes_d, &minutes); gst_util_fraction_to_double (seconds_n, seconds_d, &seconds); minutes += seconds / 60; degrees += minutes / 60; degrees *= multiplier; GST_DEBUG ("Adding %s tag: %lf", exiftag->gst_tag, degrees); gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE, exiftag->gst_tag, degrees, NULL); return ret; reader_fail: GST_WARNING ("Failed to read fields from buffer (too short?)"); return ret; }
static gboolean webKitMediaClearKeyDecryptorDecrypt(WebKitMediaCommonEncryptionDecrypt* self, GstBuffer* ivBuffer, GstBuffer* buffer, unsigned subSampleCount, GstBuffer* subSamplesBuffer) { GstMapInfo ivMap; if (!gst_buffer_map(ivBuffer, &ivMap, GST_MAP_READ)) { GST_ERROR_OBJECT(self, "Failed to map IV"); return false; } uint8_t ctr[CLEARKEY_SIZE]; if (ivMap.size == 8) { memset(ctr + 8, 0, 8); memcpy(ctr, ivMap.data, 8); } else { ASSERT(ivMap.size == CLEARKEY_SIZE); memcpy(ctr, ivMap.data, CLEARKEY_SIZE); } gst_buffer_unmap(ivBuffer, &ivMap); WebKitMediaClearKeyDecryptPrivate* priv = WEBKIT_MEDIA_CK_DECRYPT_GET_PRIVATE(WEBKIT_MEDIA_CK_DECRYPT(self)); gcry_error_t error = gcry_cipher_setctr(priv->handle, ctr, CLEARKEY_SIZE); if (error) { GST_ERROR_OBJECT(self, "gcry_cipher_setctr failed: %s", gpg_strerror(error)); return false; } GstMapInfo map; gboolean bufferMapped = gst_buffer_map(buffer, &map, static_cast<GstMapFlags>(GST_MAP_READWRITE)); if (!bufferMapped) { GST_ERROR_OBJECT(self, "Failed to map buffer"); return false; } GstMapInfo subSamplesMap; gboolean subsamplesBufferMapped = gst_buffer_map(subSamplesBuffer, &subSamplesMap, GST_MAP_READ); if (!subsamplesBufferMapped) { GST_ERROR_OBJECT(self, "Failed to map subsample buffer"); gst_buffer_unmap(buffer, &map); return false; } GstByteReader* reader = gst_byte_reader_new(subSamplesMap.data, subSamplesMap.size); unsigned position = 0; unsigned sampleIndex = 0; GST_DEBUG_OBJECT(self, "position: %d, size: %zu", position, map.size); while (position < map.size) { guint16 nBytesClear = 0; guint32 nBytesEncrypted = 0; if (sampleIndex < subSampleCount) { if (!gst_byte_reader_get_uint16_be(reader, &nBytesClear) || !gst_byte_reader_get_uint32_be(reader, &nBytesEncrypted)) { GST_DEBUG_OBJECT(self, "unsupported"); gst_byte_reader_free(reader); gst_buffer_unmap(buffer, &map); gst_buffer_unmap(subSamplesBuffer, &subSamplesMap); return false; } sampleIndex++; } else { nBytesClear = 0; nBytesEncrypted = map.size - position; } GST_TRACE_OBJECT(self, "%d bytes clear (todo=%zu)", nBytesClear, map.size - position); position += nBytesClear; if (nBytesEncrypted) { GST_TRACE_OBJECT(self, "%d bytes encrypted (todo=%zu)", nBytesEncrypted, map.size - position); error = gcry_cipher_decrypt(priv->handle, map.data + position, nBytesEncrypted, 0, 0); if (error) { GST_ERROR_OBJECT(self, "decryption failed: %s", gpg_strerror(error)); gst_byte_reader_free(reader); gst_buffer_unmap(buffer, &map); gst_buffer_unmap(subSamplesBuffer, &subSamplesMap); return false; } position += nBytesEncrypted; } } gst_byte_reader_free(reader); gst_buffer_unmap(buffer, &map); gst_buffer_unmap(subSamplesBuffer, &subSamplesMap); return true; }
static GstFlowReturn webkitMediaPlayReadyDecryptTransformInPlace(GstBaseTransform* base, GstBuffer* buffer) { WebKitMediaPlayReadyDecrypt* self = WEBKIT_MEDIA_PLAYREADY_DECRYPT(base); GstFlowReturn result = GST_FLOW_OK; GstMapInfo map; const GValue* value; guint sampleIndex = 0; int errorCode; uint32_t trackID = 0; GstPad* pad; GstCaps* caps; GstMapInfo boxMap; GstBuffer* box = nullptr; GstProtectionMeta* protectionMeta = 0; gboolean boxMapped = FALSE; gboolean bufferMapped = FALSE; GST_TRACE_OBJECT(self, "Processing buffer"); g_mutex_lock(&self->mutex); GST_TRACE_OBJECT(self, "Mutex acquired, stream received: %s", self->streamReceived ? "yes":"no"); // The key might not have been received yet. Wait for it. if (!self->streamReceived) g_cond_wait(&self->condition, &self->mutex); if (!self->streamReceived) { GST_DEBUG_OBJECT(self, "Condition signaled from state change transition. Aborting."); result = GST_FLOW_NOT_SUPPORTED; goto beach; } GST_TRACE_OBJECT(self, "Proceeding with decryption"); protectionMeta = reinterpret_cast<GstProtectionMeta*>(gst_buffer_get_protection_meta(buffer)); if (!protectionMeta || !buffer) { if (!protectionMeta) GST_ERROR_OBJECT(self, "Failed to get GstProtection metadata from buffer %p", buffer); if (!buffer) GST_ERROR_OBJECT(self, "Failed to get writable buffer"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } bufferMapped = gst_buffer_map(buffer, &map, static_cast<GstMapFlags>(GST_MAP_READWRITE)); if (!bufferMapped) { GST_ERROR_OBJECT(self, "Failed to map buffer"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } pad = gst_element_get_static_pad(GST_ELEMENT(self), "src"); caps = gst_pad_get_current_caps(pad); if (g_str_has_prefix(gst_structure_get_name(gst_caps_get_structure(caps, 0)), "video/")) trackID = 1; else trackID = 2; gst_caps_unref(caps); gst_object_unref(pad); GST_TRACE_OBJECT(self, "Protection meta: %" GST_PTR_FORMAT, protectionMeta->info); if (gst_structure_get_uint(protectionMeta->info, "sample-index", &sampleIndex)) { // Process the PIFF box. value = gst_structure_get_value(protectionMeta->info, "box"); if (!value) { GST_ERROR_OBJECT(self, "Failed to get encryption box for sample"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } box = gst_value_get_buffer(value); boxMapped = gst_buffer_map(box, &boxMap, GST_MAP_READ); if (!boxMapped) { GST_ERROR_OBJECT(self, "Failed to map encryption box"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } GST_TRACE_OBJECT(self, "decrypt sample %u", sampleIndex); if ((errorCode = self->sessionMetaData->decrypt(static_cast<void*>(map.data), static_cast<uint32_t>(map.size), static_cast<void*>(boxMap.data), static_cast<uint32_t>(boxMap.size), static_cast<uint32_t>(sampleIndex), trackID))) { GST_WARNING_OBJECT(self, "ERROR - packet decryption failed [%d]", errorCode); GST_MEMDUMP_OBJECT(self, "box", boxMap.data, boxMap.size); result = GST_FLOW_ERROR; goto beach; } } else { // Process CENC data. guint ivSize; gboolean encrypted; GstBuffer* ivBuffer = nullptr; GstMapInfo ivMap; unsigned position = 0; unsigned sampleIndex = 0; guint subSampleCount; GstBuffer* subsamplesBuffer = nullptr; GstMapInfo subSamplesMap; GstByteReader* reader = nullptr; if (!gst_structure_get_uint(protectionMeta->info, "iv_size", &ivSize)) { GST_ERROR_OBJECT(self, "failed to get iv_size"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } if (!gst_structure_get_boolean(protectionMeta->info, "encrypted", &encrypted)) { GST_ERROR_OBJECT(self, "failed to get encrypted flag"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } // Unencrypted sample. if (!ivSize || !encrypted) goto beach; if (!gst_structure_get_uint(protectionMeta->info, "subsample_count", &subSampleCount)) { GST_ERROR_OBJECT(self, "failed to get subsample_count"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } value = gst_structure_get_value(protectionMeta->info, "iv"); if (!value) { GST_ERROR_OBJECT(self, "Failed to get IV for sample"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } ivBuffer = gst_value_get_buffer(value); if (!gst_buffer_map(ivBuffer, &ivMap, GST_MAP_READ)) { GST_ERROR_OBJECT(self, "Failed to map IV"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } if (subSampleCount) { value = gst_structure_get_value(protectionMeta->info, "subsamples"); if (!value) { GST_ERROR_OBJECT(self, "Failed to get subsamples"); result = GST_FLOW_NOT_SUPPORTED; goto release; } subsamplesBuffer = gst_value_get_buffer(value); if (!gst_buffer_map(subsamplesBuffer, &subSamplesMap, GST_MAP_READ)) { GST_ERROR_OBJECT(self, "Failed to map subsample buffer"); result = GST_FLOW_NOT_SUPPORTED; goto release; } } reader = gst_byte_reader_new(subSamplesMap.data, subSamplesMap.size); if (!reader) { GST_ERROR_OBJECT(self, "Failed to allocate subsample reader"); result = GST_FLOW_NOT_SUPPORTED; goto release; } GST_DEBUG_OBJECT(self, "position: %d, size: %d", position, map.size); while (position < map.size) { guint16 nBytesClear = 0; guint32 nBytesEncrypted = 0; if (sampleIndex < subSampleCount) { if (!gst_byte_reader_get_uint16_be(reader, &nBytesClear) || !gst_byte_reader_get_uint32_be(reader, &nBytesEncrypted)) { result = GST_FLOW_NOT_SUPPORTED; GST_DEBUG_OBJECT(self, "unsupported"); goto release; } sampleIndex++; } else { nBytesClear = 0; nBytesEncrypted = map.size - position; } GST_TRACE_OBJECT(self, "%d bytes clear (todo=%d)", nBytesClear, map.size - position); position += nBytesClear; if (nBytesEncrypted) { GST_TRACE_OBJECT(self, "%d bytes encrypted (todo=%d)", nBytesEncrypted, map.size - position); if ((errorCode = self->sessionMetaData->processPayload(trackID, static_cast<const void*>(ivMap.data), static_cast<uint32_t>(ivMap.size), static_cast<void*>(map.data + position), static_cast<uint32_t>(nBytesEncrypted)))) { GST_WARNING_OBJECT(self, "ERROR - packet decryption failed [%d]", errorCode); result = GST_FLOW_ERROR; goto release; } position += nBytesEncrypted; } } release: gst_buffer_unmap(ivBuffer, &ivMap); if (reader) gst_byte_reader_free(reader); if (subsamplesBuffer) gst_buffer_unmap(subsamplesBuffer, &subSamplesMap); } beach: if (boxMapped) gst_buffer_unmap(box, &boxMap); if (bufferMapped) gst_buffer_unmap(buffer, &map); if (protectionMeta) gst_buffer_remove_meta(buffer, reinterpret_cast<GstMeta*>(protectionMeta)); GST_TRACE_OBJECT(self, "Unlocking mutex"); g_mutex_unlock(&self->mutex); return result; }
static gboolean gst_dirac_parse_check_valid_frame (GstBaseParse * parse, GstBaseParseFrame * frame, guint * framesize, gint * skipsize) { GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (frame->buffer); GstDiracParse *diracparse = GST_DIRAC_PARSE (parse); int off; guint32 next_header; gboolean sync; gboolean drain; if (G_UNLIKELY (GST_BUFFER_SIZE (frame->buffer) < 13)) return FALSE; off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, 0x42424344, 0, GST_BUFFER_SIZE (frame->buffer)); if (off < 0) { *skipsize = GST_BUFFER_SIZE (frame->buffer) - 3; return FALSE; } GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off); if (off > 0) { GST_ERROR ("skipping %d", off); *skipsize = off; return FALSE; } if (!gst_dirac_parse_frame_header (diracparse, frame->buffer, framesize)) { GST_ERROR ("bad header"); *skipsize = 3; return FALSE; } GST_LOG ("framesize %d", *framesize); sync = GST_BASE_PARSE_FRAME_SYNC (frame); drain = GST_BASE_PARSE_FRAME_DRAIN (frame); if (!sync && !drain) { guint32 next_sync_word = 0; next_header = GST_READ_UINT32_BE (GST_BUFFER_DATA (frame->buffer) + 5); GST_LOG ("next header %d", next_header); if (!gst_byte_reader_skip (&reader, next_header) || !gst_byte_reader_get_uint32_be (&reader, &next_sync_word)) { gst_base_parse_set_min_frame_size (parse, next_header + 4); *skipsize = 0; return FALSE; } else { if (next_sync_word != 0x42424344) { *skipsize = 3; return FALSE; } else { gst_base_parse_set_min_frame_size (parse, next_header); } } } return TRUE; }
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; }
static GstFlowReturn gst_cenc_decrypt_transform_ip (GstBaseTransform * base, GstBuffer * buf) { GstCencDecrypt *self = GST_CENC_DECRYPT (base); GstFlowReturn ret = GST_FLOW_OK; GstMapInfo map, iv_map; const GstCencKeyPair *keypair; const GstProtectionMeta *prot_meta = NULL; guint pos = 0; gint sample_index = 0; guint subsample_count; AesCtrState *state = NULL; guint iv_size; gboolean encrypted; const GValue *value; GstBuffer *key_id = NULL; GstBuffer *iv_buf = NULL; GBytes *iv_bytes = NULL; GstBuffer *subsamples_buf = NULL; GstMapInfo subsamples_map; GstByteReader *reader=NULL; GST_TRACE_OBJECT (self, "decrypt in-place"); prot_meta = (GstProtectionMeta*) gst_buffer_get_protection_meta (buf); if (!prot_meta || !buf) { if (!prot_meta) { GST_ERROR_OBJECT (self, "Failed to get GstProtection metadata from buffer"); } if (!buf) { GST_ERROR_OBJECT (self, "Failed to get writable buffer"); } ret = GST_FLOW_NOT_SUPPORTED; goto out; } if (!gst_buffer_map (buf, &map, GST_MAP_READWRITE)) { GST_ERROR_OBJECT (self, "Failed to map buffer"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } GST_TRACE_OBJECT (self, "decrypt sample %d", (gint)map.size); if(!gst_structure_get_uint(prot_meta->info,"iv_size",&iv_size)){ GST_ERROR_OBJECT (self, "failed to get iv_size"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } if(!gst_structure_get_boolean(prot_meta->info,"encrypted",&encrypted)){ GST_ERROR_OBJECT (self, "failed to get encrypted flag"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } if (iv_size == 0 || !encrypted) { /* sample is not encrypted */ goto beach; } GST_DEBUG_OBJECT (base, "protection meta: %" GST_PTR_FORMAT, prot_meta->info); if(!gst_structure_get_uint(prot_meta->info,"subsample_count",&subsample_count)){ GST_ERROR_OBJECT (self, "failed to get subsample_count"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } value = gst_structure_get_value (prot_meta->info, "kid"); if(!value){ GST_ERROR_OBJECT (self, "Failed to get KID for sample"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } key_id = gst_value_get_buffer (value); value = gst_structure_get_value (prot_meta->info, "iv"); if(!value){ GST_ERROR_OBJECT (self, "Failed to get IV for sample"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } iv_buf = gst_value_get_buffer (value); if(!gst_buffer_map (iv_buf, &iv_map, GST_MAP_READ)){ GST_ERROR_OBJECT (self, "Failed to map IV"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } iv_bytes = g_bytes_new (iv_map.data, iv_map.size); gst_buffer_unmap (iv_buf, &iv_map); if(subsample_count){ value = gst_structure_get_value (prot_meta->info, "subsamples"); if(!value){ GST_ERROR_OBJECT (self, "Failed to get subsamples"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } subsamples_buf = gst_value_get_buffer (value); if(!gst_buffer_map (subsamples_buf, &subsamples_map, GST_MAP_READ)){ GST_ERROR_OBJECT (self, "Failed to map subsample buffer"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } } keypair = gst_cenc_decrypt_lookup_key (self,key_id); if (!keypair) { gsize sz; GST_ERROR_OBJECT (self, "Failed to lookup key"); GST_MEMDUMP_OBJECT (self, "Key ID:", g_bytes_get_data (keypair->key_id, &sz), sz); ret = GST_FLOW_NOT_SUPPORTED; goto release; } state = gst_aes_ctr_decrypt_new (keypair->key, iv_bytes); if (!state) { GST_ERROR_OBJECT (self, "Failed to init AES cipher"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } if (subsample_count) { reader = gst_byte_reader_new (subsamples_map.data, subsamples_map.size); if(!reader){ GST_ERROR_OBJECT (self, "Failed to allocate subsample reader"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } } while (pos < map.size) { guint16 n_bytes_clear = 0; guint32 n_bytes_encrypted = 0; if (sample_index < subsample_count) { if (!gst_byte_reader_get_uint16_be (reader, &n_bytes_clear) || !gst_byte_reader_get_uint32_be (reader, &n_bytes_encrypted)) { ret = GST_FLOW_NOT_SUPPORTED; goto release; } sample_index++; } else { n_bytes_clear = 0; n_bytes_encrypted = map.size - pos; } GST_TRACE_OBJECT (self, "%u bytes clear (todo=%d)", n_bytes_clear, (gint)map.size - pos); pos += n_bytes_clear; if (n_bytes_encrypted) { GST_TRACE_OBJECT (self, "%u bytes encrypted (todo=%d)", n_bytes_encrypted, (gint)map.size - pos); gst_aes_ctr_decrypt_ip (state, map.data + pos, n_bytes_encrypted); pos += n_bytes_encrypted; } } beach: gst_buffer_unmap (buf, &map); if (state) { gst_aes_ctr_decrypt_unref (state); } release: if (reader){ gst_byte_reader_free (reader); } if(subsamples_buf){ gst_buffer_unmap (subsamples_buf, &subsamples_map); } if (prot_meta) { gst_buffer_remove_meta (buf, (GstMeta *) prot_meta); } if (iv_bytes) { g_bytes_unref (iv_bytes); } out: return ret; }
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; }