static void gst_compare_buffers (GstCompare * comp, GstBuffer * buf1, GstCaps * caps1, GstBuffer * buf2, GstCaps * caps2) { gdouble delta = 0; gsize size1, size2; /* first check metadata */ gst_compare_meta (comp, buf1, caps1, buf2, caps2); size1 = gst_buffer_get_size (buf1); size2 = gst_buffer_get_size (buf1); /* check content according to method */ /* but at least size should match */ if (size1 != size2) { delta = comp->threshold + 1; } else { GstMapInfo map1, map2; gst_buffer_map (buf1, &map1, GST_MAP_READ); gst_buffer_map (buf2, &map2, GST_MAP_READ); GST_MEMDUMP_OBJECT (comp, "buffer 1", map1.data, map2.size); GST_MEMDUMP_OBJECT (comp, "buffer 2", map2.data, map2.size); gst_buffer_unmap (buf1, &map1); gst_buffer_unmap (buf2, &map2); switch (comp->method) { case GST_COMPARE_METHOD_MEM: delta = gst_compare_mem (comp, buf1, caps1, buf2, caps2); break; case GST_COMPARE_METHOD_MAX: delta = gst_compare_max (comp, buf1, caps1, buf2, caps2); break; case GST_COMPARE_METHOD_SSIM: delta = gst_compare_ssim (comp, buf1, caps1, buf2, caps2); break; default: g_assert_not_reached (); break; } } if ((comp->upper && delta > comp->threshold) || (!comp->upper && delta < comp->threshold)) { GST_WARNING_OBJECT (comp, "buffers %p and %p failed content match %f", buf1, buf2, delta); gst_element_post_message (GST_ELEMENT (comp), gst_message_new_element (GST_OBJECT (comp), gst_structure_new ("delta", "content", G_TYPE_DOUBLE, delta, NULL))); } }
static int gst_curl_base_sink_debug_cb (CURL * handle, curl_infotype type, char *data, size_t size, void *clientp) { GstCurlBaseSink *sink = (GstCurlBaseSink *) clientp; gchar *msg = NULL; switch (type) { case CURLINFO_TEXT: case CURLINFO_HEADER_IN: case CURLINFO_HEADER_OUT: msg = g_memdup (data, size); if (size > 0) { msg[size - 1] = '\0'; g_strchomp (msg); } break; default: break; } switch (type) { case CURLINFO_TEXT: GST_DEBUG_OBJECT (sink, "%s", msg); break; case CURLINFO_HEADER_IN: GST_DEBUG_OBJECT (sink, "incoming header: %s", msg); break; case CURLINFO_HEADER_OUT: GST_DEBUG_OBJECT (sink, "outgoing header: %s", msg); break; case CURLINFO_DATA_IN: GST_MEMDUMP_OBJECT (sink, "incoming data", (guint8 *) data, size); break; case CURLINFO_DATA_OUT: GST_MEMDUMP_OBJECT (sink, "outgoing data", (guint8 *) data, size); break; case CURLINFO_SSL_DATA_IN: GST_MEMDUMP_OBJECT (sink, "incoming ssl data", (guint8 *) data, size); break; case CURLINFO_SSL_DATA_OUT: GST_MEMDUMP_OBJECT (sink, "outgoing ssl data", (guint8 *) data, size); break; default: GST_DEBUG_OBJECT (sink, "unknown debug info type %d", type); GST_MEMDUMP_OBJECT (sink, "unknown data", (guint8 *) data, size); break; } g_free (msg); return 0; }
static void gst_compare_buffers (GstCompare * comp, GstBuffer * buf1, GstBuffer * buf2) { gdouble delta = 0; /* first check metadata */ gst_compare_meta (comp, buf1, buf2); /* check content according to method */ /* but at least size should match */ if (GST_BUFFER_SIZE (buf1) != GST_BUFFER_SIZE (buf2)) { delta = comp->threshold + 1; } else { GST_MEMDUMP_OBJECT (comp, "buffer 1", GST_BUFFER_DATA (buf1), GST_BUFFER_SIZE (buf1)); GST_MEMDUMP_OBJECT (comp, "buffer 2", GST_BUFFER_DATA (buf2), GST_BUFFER_SIZE (buf2)); switch (comp->method) { case GST_COMPARE_METHOD_MEM: delta = gst_compare_mem (comp, buf1, buf2); break; case GST_COMPARE_METHOD_MAX: delta = gst_compare_max (comp, buf1, buf2); break; case GST_COMPARE_METHOD_SSIM: delta = gst_compare_ssim (comp, buf1, buf2); break; default: g_assert_not_reached (); break; } } if ((comp->upper && delta > comp->threshold) || (!comp->upper && delta < comp->threshold)) { GST_WARNING_OBJECT (comp, "buffers %p and %p failed content match %f", buf1, buf2, delta); gst_element_post_message (GST_ELEMENT (comp), gst_message_new_element (GST_OBJECT (comp), gst_structure_new ("delta", "content", G_TYPE_DOUBLE, delta, NULL))); } }
static gboolean gst_ac3_parse_frame_header (GstAc3Parse * parse, GstBuffer * buf, gint skip, guint * framesize, guint * rate, guint * chans, guint * blocks, guint * sid, gboolean * eac) { GstBitReader bits; guint16 sync; guint8 bsid; GstMapInfo map; gboolean ret = FALSE; gst_buffer_map (buf, &map, GST_MAP_READ); gst_bit_reader_init (&bits, map.data, map.size); GST_MEMDUMP_OBJECT (parse, "AC3 frame sync", map.data, MIN (map.size, 16)); gst_bit_reader_skip_unchecked (&bits, skip * 8); sync = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16); gst_bit_reader_skip_unchecked (&bits, 16 + 8); bsid = gst_bit_reader_peek_bits_uint8_unchecked (&bits, 5); if (G_UNLIKELY (sync != 0x0b77)) goto cleanup; GST_LOG_OBJECT (parse, "bsid = %d", bsid); if (bsid <= 10) { if (eac) *eac = FALSE; ret = gst_ac3_parse_frame_header_ac3 (parse, buf, skip, framesize, rate, chans, blocks, sid); goto cleanup; } else if (bsid <= 16) { if (eac) *eac = TRUE; ret = gst_ac3_parse_frame_header_eac3 (parse, buf, skip, framesize, rate, chans, blocks, sid); goto cleanup; } else { GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid); ret = FALSE; goto cleanup; } GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid); cleanup: gst_buffer_unmap (buf, &map); return ret; }
static gboolean gst_ac3_parse_frame_header (GstAc3Parse * parse, GstBuffer * buf, gint skip, guint * framesize, guint * rate, guint * chans, guint * blocks, guint * sid, gboolean * eac) { GstBitReader bits = GST_BIT_READER_INIT_FROM_BUFFER (buf); guint16 sync; guint8 bsid; GST_MEMDUMP_OBJECT (parse, "AC3 frame sync", GST_BUFFER_DATA (buf), 16); gst_bit_reader_skip_unchecked (&bits, skip * 8); sync = gst_bit_reader_get_bits_uint16_unchecked (&bits, 16); gst_bit_reader_skip_unchecked (&bits, 16 + 8); bsid = gst_bit_reader_peek_bits_uint8_unchecked (&bits, 5); if (G_UNLIKELY (sync != 0x0b77)) return FALSE; GST_LOG_OBJECT (parse, "bsid = %d", bsid); if (bsid <= 10) { if (eac) *eac = FALSE; return gst_ac3_parse_frame_header_ac3 (parse, buf, skip, framesize, rate, chans, blocks, sid); } else if (bsid <= 16) { if (eac) *eac = TRUE; return gst_ac3_parse_frame_header_eac3 (parse, buf, skip, framesize, rate, chans, blocks, sid); } else { GST_DEBUG_OBJECT (parse, "unexpected bsid %d", bsid); return FALSE; } }
static void handle_buffer (GstFluidDec * fluiddec, GstBuffer * buffer) { GstMapInfo info; guint8 event; gst_buffer_map (buffer, &info, GST_MAP_READ); event = info.data[0]; switch (event & 0xf0) { case 0xf0: switch (event) { case 0xff: GST_DEBUG_OBJECT (fluiddec, "system reset"); fluid_synth_system_reset (fluiddec->synth); break; case 0xf0: case 0xf7: GST_DEBUG_OBJECT (fluiddec, "sysex 0x%02x", event); GST_MEMDUMP_OBJECT (fluiddec, "bytes ", info.data + 1, info.size - 1); fluid_synth_sysex (fluiddec->synth, (char *) info.data + 1, info.size - 1, NULL, NULL, NULL, 0); break; case 0xf9: GST_LOG_OBJECT (fluiddec, "midi tick"); break; default: GST_WARNING_OBJECT (fluiddec, "unhandled event 0x%02x", event); break; } break; default: { guint8 channel, p1, p2; channel = event & 0x0f; p1 = info.size > 1 ? info.data[1] & 0x7f : 0; p2 = info.size > 2 ? info.data[2] & 0x7f : 0; GST_DEBUG_OBJECT (fluiddec, "event 0x%02x channel %d, 0x%02x 0x%02x", event, channel, p1, p2); switch (event & 0xf0) { case 0x80: fluid_synth_noteoff (fluiddec->synth, channel, p1); break; case 0x90: fluid_synth_noteon (fluiddec->synth, channel, p1, p2); break; case 0xA0: /* aftertouch */ break; case 0xB0: fluid_synth_cc (fluiddec->synth, channel, p1, p2); break; case 0xC0: fluid_synth_program_change (fluiddec->synth, channel, p1); break; case 0xD0: fluid_synth_channel_pressure (fluiddec->synth, channel, p1); break; case 0xE0: fluid_synth_pitch_bend (fluiddec->synth, channel, (p2 << 7) | p1); break; default: break; } break; } } gst_buffer_unmap (buffer, &info); }
static GstBuffer * gst_rtp_vp9_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp) { GstRtpVP9Depay *self = GST_RTP_VP9_DEPAY (depay); GstBuffer *payload; guint8 *data; guint hdrsize = 1; guint size; gint spatial_layer = 0; gboolean i_bit, p_bit, l_bit, f_bit, b_bit, e_bit, v_bit; if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (rtp->buffer))) { GST_LOG_OBJECT (self, "Discontinuity, flushing adapter"); gst_adapter_clear (self->adapter); self->started = FALSE; } size = gst_rtp_buffer_get_payload_len (rtp); /* Mandatory with at least one header and one vp9 byte */ if (G_UNLIKELY (size < hdrsize + 1)) goto too_small; data = gst_rtp_buffer_get_payload (rtp); i_bit = (data[0] & 0x80) != 0; p_bit = (data[0] & 0x40) != 0; l_bit = (data[0] & 0x20) != 0; f_bit = (data[0] & 0x10) != 0; b_bit = (data[0] & 0x08) != 0; e_bit = (data[0] & 0x04) != 0; v_bit = (data[0] & 0x02) != 0; if (G_UNLIKELY (!self->started)) { /* Check if this is the start of a VP9 layer frame, otherwise bail */ if (!b_bit) goto done; self->started = TRUE; } GST_TRACE_OBJECT (self, "IPLFBEV : %d%d%d%d%d%d%d", i_bit, p_bit, l_bit, f_bit, b_bit, e_bit, v_bit); /* Check I optional header Picture ID */ if (i_bit) { hdrsize++; if (G_UNLIKELY (size < hdrsize + 1)) goto too_small; /* Check M for 15 bits PictureID */ if ((data[1] & 0x80) != 0) { hdrsize++; if (G_UNLIKELY (size < hdrsize + 1)) goto too_small; } } /* flexible-mode not implemented */ g_assert (!f_bit); /* Check L optional header layer indices */ if (l_bit) { hdrsize++; /* Check TL0PICIDX temporal layer zero index (non-flexible mode) */ if (!f_bit) hdrsize++; } /* Check V optional Scalability Structure */ if (v_bit) { guint n_s, y_bit, g_bit; guint8 *ss = &data[hdrsize]; guint sssize = 1; if (G_UNLIKELY (size < hdrsize + sssize + 1)) goto too_small; n_s = (ss[0] & 0xe0) >> 5; y_bit = (ss[0] & 0x10) != 0; g_bit = (ss[0] & 0x08) != 0; GST_TRACE_OBJECT (self, "SS header: N_S=%u, Y=%u, G=%u", n_s, y_bit, g_bit); sssize += y_bit ? (n_s + 1) * 4 : 0; if (G_UNLIKELY (size < hdrsize + sssize + 1)) goto too_small; if (y_bit) { guint i; for (i = 0; i <= n_s; i++) { /* For now, simply use the last layer specified for width and height */ self->ss_width = ss[1 + i * 4] * 256 + ss[2 + i * 4]; self->ss_height = ss[3 + i * 4] * 256 + ss[4 + i * 4]; GST_TRACE_OBJECT (self, "N_S[%d]: WIDTH=%u, HEIGHT=%u", i, self->ss_width, self->ss_height); } } if (g_bit) { guint i, j; guint n_g = ss[sssize]; sssize++; if (G_UNLIKELY (size < hdrsize + sssize + 1)) goto too_small; for (i = 0; i < n_g; i++) { guint t = (ss[sssize] & 0xe0) >> 5; guint u = (ss[sssize] & 0x10) >> 4; guint r = (ss[sssize] & 0x0c) >> 2; GST_TRACE_OBJECT (self, "N_G[%u]: 0x%02x -> T=%u, U=%u, R=%u", i, ss[sssize], t, u, r); for (j = 0; j < r; j++) GST_TRACE_OBJECT (self, " R[%u]: P_DIFF=%u", j, ss[sssize + 1 + j]); sssize += 1 + r; if (G_UNLIKELY (size < hdrsize + sssize + 1)) goto too_small; } } hdrsize += sssize; } GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size); if (G_UNLIKELY (hdrsize >= size)) goto too_small; payload = gst_rtp_buffer_get_payload_subbuffer (rtp, hdrsize, -1); { GstMapInfo map; gst_buffer_map (payload, &map, GST_MAP_READ); GST_MEMDUMP_OBJECT (self, "vp9 payload", map.data, 16); gst_buffer_unmap (payload, &map); } gst_adapter_push (self->adapter, payload); /* Marker indicates that it was the last rtp packet for this frame */ if (gst_rtp_buffer_get_marker (rtp)) { GstBuffer *out; gboolean key_frame_first_layer = !p_bit && spatial_layer == 0; if (gst_adapter_available (self->adapter) < 10) goto too_small; out = gst_adapter_take_buffer (self->adapter, gst_adapter_available (self->adapter)); self->started = FALSE; /* mark keyframes */ out = gst_buffer_make_writable (out); /* Filter away all metas that are not sensible to copy */ gst_rtp_drop_meta (GST_ELEMENT_CAST (self), out, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); if (!key_frame_first_layer) { GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT); if (!self->caps_sent) { gst_buffer_unref (out); out = NULL; GST_INFO_OBJECT (self, "Dropping inter-frame before intra-frame"); gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depay), gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, TRUE, 0)); } } else { GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT); if (self->last_width != self->ss_width || self->last_height != self->ss_height) { GstCaps *srccaps; /* Width and height are optional in the RTP header. Consider to parse * the frame header in addition if missing from RTP header */ if (self->ss_width != 0 && self->ss_height != 0) { srccaps = gst_caps_new_simple ("video/x-vp9", "framerate", GST_TYPE_FRACTION, 0, 1, "width", G_TYPE_INT, self->ss_width, "height", G_TYPE_INT, self->ss_height, NULL); } else { srccaps = gst_caps_new_simple ("video/x-vp9", "framerate", GST_TYPE_FRACTION, 0, 1, NULL); } gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps); gst_caps_unref (srccaps); self->caps_sent = TRUE; self->last_width = self->ss_width; self->last_height = self->ss_height; self->ss_width = 0; self->ss_height = 0; } } return out; } done: return NULL; too_small: GST_LOG_OBJECT (self, "Invalid rtp packet (too small), ignoring"); gst_adapter_clear (self->adapter); self->started = FALSE; goto done; }
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 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 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); if (!gst_structure_get_uint(protectionMeta->info, "sample-index", &sampleIndex)) { GST_ERROR_OBJECT(self, "failed to get sample-index"); result = GST_FLOW_NOT_SUPPORTED; goto beach; } 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; } 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_ssa_parse_setcaps (GstPad * sinkpad, GstCaps * caps) { GstSsaParse *parse = GST_SSA_PARSE (GST_PAD_PARENT (sinkpad)); GstCaps *outcaps; const GValue *val; GstStructure *s; const guchar bom_utf8[] = { 0xEF, 0xBB, 0xBF }; const gchar *end; GstBuffer *priv; GstMapInfo map; gchar *ptr; gsize left, bad_offset; gboolean ret; s = gst_caps_get_structure (caps, 0); val = gst_structure_get_value (s, "codec_data"); if (val == NULL) { parse->framed = FALSE; GST_ERROR ("Only SSA subtitles embedded in containers are supported"); return FALSE; } parse->framed = TRUE; parse->send_tags = TRUE; priv = (GstBuffer *) g_value_get_boxed (val); g_return_val_if_fail (priv != NULL, FALSE); gst_buffer_ref (priv); if (!gst_buffer_map (priv, &map, GST_MAP_READ)) return FALSE; GST_MEMDUMP_OBJECT (parse, "init section", map.data, map.size); ptr = (gchar *) map.data; left = map.size; /* skip UTF-8 BOM */ if (left >= 3 && memcmp (ptr, bom_utf8, 3) == 0) { ptr += 3; left -= 3; } if (!strstr (ptr, "[Script Info]")) goto invalid_init; if (!g_utf8_validate (ptr, left, &end)) { bad_offset = (gsize) (end - ptr); GST_WARNING_OBJECT (parse, "Init section is not valid UTF-8. Problem at " "byte offset %" G_GSIZE_FORMAT, bad_offset); /* continue with valid UTF-8 data */ left = bad_offset; } /* FIXME: parse initial section */ parse->ini = g_strndup (ptr, left); GST_LOG_OBJECT (parse, "Init section:\n%s", parse->ini); gst_buffer_unmap (priv, &map); gst_buffer_unref (priv); outcaps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, "pango-markup", NULL); ret = gst_pad_set_caps (parse->srcpad, outcaps); gst_caps_unref (outcaps); return ret; /* ERRORS */ invalid_init: { GST_WARNING_OBJECT (parse, "Invalid Init section - no Script Info header"); gst_buffer_unmap (priv, &map); gst_buffer_unref (priv); return FALSE; } }
/** * gst_riff_parse_info: * @element: caller element (used for debugging/error). * @buf: input data to be used for parsing, stripped from header. * @taglist: a pointer to a taglist (returned by this function) * containing information about this stream. May be * NULL if no supported tags were found. * * Parses stream metadata from input data. */ void gst_riff_parse_info (GstElement * element, GstBuffer * buf, GstTagList ** _taglist) { guint8 *data; guint size, tsize; guint32 tag; const gchar *type; GstTagList *taglist; g_return_if_fail (_taglist != NULL); if (!buf) { *_taglist = NULL; return; } data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); taglist = gst_tag_list_new (); while (size > 8) { tag = GST_READ_UINT32_LE (data); tsize = GST_READ_UINT32_LE (data + 4); GST_MEMDUMP_OBJECT (element, "tag chunk", data, MIN (tsize + 8, size)); size -= 8; data += 8; GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u", GST_FOURCC_ARGS (tag), tsize); if (tsize > size) { GST_WARNING_OBJECT (element, "Tagsize %d is larger than available data %d", tsize, size); tsize = size; } /* make uppercase */ tag = tag & 0xDFDFDFDF; /* find out the type of metadata */ switch (tag) { case GST_RIFF_INFO_IARL: type = GST_TAG_LOCATION; break; case GST_RIFF_INFO_IAAR: type = GST_TAG_ALBUM_ARTIST; break; case GST_RIFF_INFO_IART: type = GST_TAG_ARTIST; break; case GST_RIFF_INFO_ICMS: type = NULL; /*"Commissioner"; */ break; case GST_RIFF_INFO_ICMT: type = GST_TAG_COMMENT; break; case GST_RIFF_INFO_ICOP: type = GST_TAG_COPYRIGHT; break; case GST_RIFF_INFO_ICRD: type = GST_TAG_DATE; break; case GST_RIFF_INFO_ICRP: type = NULL; /*"Cropped"; */ break; case GST_RIFF_INFO_IDIM: type = NULL; /*"Dimensions"; */ break; case GST_RIFF_INFO_IDPI: type = NULL; /*"Dots per Inch"; */ break; case GST_RIFF_INFO_IENG: type = NULL; /*"Engineer"; */ break; case GST_RIFF_INFO_IGNR: type = GST_TAG_GENRE; break; case GST_RIFF_INFO_IKEY: type = GST_TAG_KEYWORDS; break; case GST_RIFF_INFO_ILGT: type = NULL; /*"Lightness"; */ break; case GST_RIFF_INFO_IMED: type = NULL; /*"Medium"; */ break; case GST_RIFF_INFO_INAM: type = GST_TAG_TITLE; break; case GST_RIFF_INFO_IPLT: type = NULL; /*"Palette"; */ break; case GST_RIFF_INFO_IPRD: type = GST_TAG_ALBUM; break; case GST_RIFF_INFO_ISBJ: type = GST_TAG_ALBUM_ARTIST; break; case GST_RIFF_INFO_ISFT: type = GST_TAG_ENCODER; break; case GST_RIFF_INFO_ISHP: type = NULL; /*"Sharpness"; */ break; case GST_RIFF_INFO_ISRC: type = GST_TAG_ISRC; break; case GST_RIFF_INFO_ISRF: type = NULL; /*"Source Form"; */ break; case GST_RIFF_INFO_ITCH: type = NULL; /*"Technician"; */ break; case GST_RIFF_INFO_ITRK: type = GST_TAG_TRACK_NUMBER; break; default: type = NULL; GST_WARNING_OBJECT (element, "Unknown INFO (metadata) tag entry %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)); break; } if (type != NULL && data[0] != '\0') { static const gchar *env_vars[] = { "GST_AVI_TAG_ENCODING", "GST_RIFF_TAG_ENCODING", "GST_TAG_ENCODING", NULL }; GType tag_type; gchar *val; GST_DEBUG_OBJECT (element, "mapped tag %" GST_FOURCC_FORMAT " to tag %s", GST_FOURCC_ARGS (tag), type); tag_type = gst_tag_get_type (type); val = gst_tag_freeform_string_to_utf8 ((gchar *) data, tsize, env_vars); if (val != NULL) { if (tag_type == G_TYPE_STRING) { gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, type, val, NULL); } else { GValue tag_val = { 0, }; g_value_init (&tag_val, tag_type); if (gst_value_deserialize (&tag_val, val)) { gst_tag_list_add_value (taglist, GST_TAG_MERGE_APPEND, type, &tag_val); } else { GST_WARNING_OBJECT (element, "could not deserialize '%s' into a " "tag %s of type %s", val, type, g_type_name (tag_type)); } g_value_unset (&tag_val); } g_free (val); } else { GST_WARNING_OBJECT (element, "could not extract %s tag", type); } } if (tsize & 1) { tsize++; if (tsize > size) tsize = size; } data += tsize; size -= tsize; } if (!gst_tag_list_is_empty (taglist)) { GST_INFO_OBJECT (element, "extracted tags: %" GST_PTR_FORMAT, taglist); *_taglist = taglist; } else { *_taglist = NULL; gst_tag_list_free (taglist); } return; }