static GstFlowReturn gst_y4m_dec_chain (GstPad * pad, GstBuffer * buffer) { GstY4mDec *y4mdec; int n_avail; GstFlowReturn flow_ret = GST_FLOW_OK; #define MAX_HEADER_LENGTH 80 char header[MAX_HEADER_LENGTH]; int i; int len; y4mdec = GST_Y4M_DEC (gst_pad_get_parent (pad)); GST_DEBUG_OBJECT (y4mdec, "chain"); if (GST_BUFFER_IS_DISCONT (buffer)) { GST_DEBUG ("got discont"); gst_adapter_clear (y4mdec->adapter); } gst_adapter_push (y4mdec->adapter, buffer); n_avail = gst_adapter_available (y4mdec->adapter); if (!y4mdec->have_header) { gboolean ret; GstCaps *caps; if (n_avail < MAX_HEADER_LENGTH) return GST_FLOW_OK; gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); header[MAX_HEADER_LENGTH - 1] = 0; for (i = 0; i < MAX_HEADER_LENGTH; i++) { if (header[i] == 0x0a) header[i] = 0; } ret = gst_y4m_dec_parse_header (y4mdec, header); if (!ret) { GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, ("Failed to parse YUV4MPEG header"), (NULL)); return GST_FLOW_ERROR; } y4mdec->header_size = strlen (header) + 1; gst_adapter_flush (y4mdec->adapter, y4mdec->header_size); caps = gst_video_format_new_caps_interlaced (y4mdec->format, y4mdec->width, y4mdec->height, y4mdec->fps_n, y4mdec->fps_d, y4mdec->par_n, y4mdec->par_d, y4mdec->interlaced); ret = gst_pad_set_caps (y4mdec->srcpad, caps); gst_caps_unref (caps); if (!ret) { GST_DEBUG_OBJECT (y4mdec, "Couldn't set caps on src pad"); return GST_FLOW_ERROR; } y4mdec->have_header = TRUE; } if (y4mdec->have_new_segment) { GstEvent *event; GstClockTime start = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment_start); GstClockTime stop = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment_stop); GstClockTime position = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment_position); event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, start, stop, position); gst_pad_push_event (y4mdec->srcpad, event); //gst_event_unref (event); y4mdec->have_new_segment = FALSE; y4mdec->frame_index = gst_y4m_dec_bytes_to_frames (y4mdec, y4mdec->segment_position); GST_DEBUG ("new frame_index %d", y4mdec->frame_index); } while (1) { n_avail = gst_adapter_available (y4mdec->adapter); if (n_avail < MAX_HEADER_LENGTH) break; gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); header[MAX_HEADER_LENGTH - 1] = 0; for (i = 0; i < MAX_HEADER_LENGTH; i++) { if (header[i] == 0x0a) header[i] = 0; } if (memcmp (header, "FRAME", 5) != 0) { GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, ("Failed to parse YUV4MPEG frame"), (NULL)); flow_ret = GST_FLOW_ERROR; break; } len = strlen (header); if (n_avail < y4mdec->frame_size + len + 1) { /* not enough data */ GST_DEBUG ("not enough data for frame %d < %d", n_avail, y4mdec->frame_size + len + 1); break; } gst_adapter_flush (y4mdec->adapter, len + 1); buffer = gst_adapter_take_buffer (y4mdec->adapter, y4mdec->frame_size); GST_BUFFER_CAPS (buffer) = gst_caps_ref (GST_PAD_CAPS (y4mdec->srcpad)); GST_BUFFER_TIMESTAMP (buffer) = gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index); GST_BUFFER_DURATION (buffer) = gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index + 1) - GST_BUFFER_TIMESTAMP (buffer); if (y4mdec->interlaced && y4mdec->tff) { GST_BUFFER_FLAG_SET (buffer, GST_VIDEO_BUFFER_TFF); } y4mdec->frame_index++; flow_ret = gst_pad_push (y4mdec->srcpad, buffer); if (flow_ret != GST_FLOW_OK) break; } gst_object_unref (y4mdec); GST_DEBUG ("returning %d", flow_ret); return flow_ret; }
static GstBuffer * gst_rtp_xqt_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf) { GstRtpXQTDepay *rtpxqtdepay; GstBuffer *outbuf = NULL; gboolean m; GstRTPBuffer rtp = { NULL }; rtpxqtdepay = GST_RTP_XQT_DEPAY (depayload); gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; if (GST_BUFFER_IS_DISCONT (buf)) { /* discont, clear adapter and try to find a new packet start */ gst_adapter_clear (rtpxqtdepay->adapter); rtpxqtdepay->need_resync = TRUE; GST_DEBUG_OBJECT (rtpxqtdepay, "we need resync"); } m = gst_rtp_buffer_get_marker (&rtp); GST_LOG_OBJECT (rtpxqtdepay, "marker: %d", m); { gint payload_len; guint avail; guint8 *payload; guint8 ver, pck; gboolean s, q, l, d; payload_len = gst_rtp_buffer_get_payload_len (&rtp); payload = gst_rtp_buffer_get_payload (&rtp); /* 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | VER |PCK|S|Q|L| RES |D| QuickTime Payload ID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (payload_len <= 4) goto wrong_length; ver = (payload[0] & 0xf0) >> 4; if (ver > 1) goto wrong_version; pck = (payload[0] & 0x0c) >> 2; if (pck == 0) goto pck_reserved; s = (payload[0] & 0x02) != 0; /* contains sync sample */ q = (payload[0] & 0x01) != 0; /* has payload description */ l = (payload[1] & 0x80) != 0; /* has packet specific information description */ d = (payload[2] & 0x80) != 0; /* don't cache info for payload id */ /* id used for caching info */ rtpxqtdepay->current_id = ((payload[2] & 0x7f) << 8) | payload[3]; GST_LOG_OBJECT (rtpxqtdepay, "VER: %d, PCK: %d, S: %d, Q: %d, L: %d, D: %d, ID: %d", ver, pck, s, q, l, d, rtpxqtdepay->current_id); if (rtpxqtdepay->need_resync) { /* we need to find the boundary of a new packet after a DISCONT */ if (pck != 3 || q) { /* non-fragmented packet or payload description present, packet starts * here. */ rtpxqtdepay->need_resync = FALSE; } else { /* fragmented packet without description */ if (m) { /* marker bit set, next packet is start of new one */ rtpxqtdepay->need_resync = FALSE; } goto need_resync; } } payload += 4; payload_len -= 4; if (q) { gboolean k, f, a, z; guint pdlen, pdpadded; gint padding; /* media_type only used for printing */ guint32 G_GNUC_UNUSED media_type; guint32 timescale; /* 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |K|F|A|Z| RES | QuickTime Payload Desc Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime Payload Desc Data ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (payload_len <= 4) goto wrong_length; k = (payload[0] & 0x80) != 0; /* keyframe */ f = (payload[0] & 0x40) != 0; /* sparse */ a = (payload[0] & 0x20) != 0; /* start of payload */ z = (payload[0] & 0x10) != 0; /* end of payload */ pdlen = (payload[2] << 8) | payload[3]; if (pdlen < 12) goto wrong_length; /* calc padding */ pdpadded = pdlen + 3; pdpadded -= pdpadded % 4; if (payload_len < pdpadded) goto wrong_length; padding = pdpadded - pdlen; GST_LOG_OBJECT (rtpxqtdepay, "K: %d, F: %d, A: %d, Z: %d, len: %d, padding %d", k, f, a, z, pdlen, padding); payload += 4; payload_len -= 4; /* 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | QuickTime Media Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Timescale | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime TLVs ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ media_type = (payload[0] << 24) | (payload[1] << 16) | (payload[2] << 8) | payload[3]; timescale = (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) | payload[7]; GST_LOG_OBJECT (rtpxqtdepay, "media_type: %c%c%c%c, timescale %u", payload[0], payload[1], payload[2], payload[3], timescale); payload += 8; payload_len -= 8; pdlen -= 12; /* parse TLV (type-length-value triplets */ while (pdlen > 3) { guint16 tlv_len, tlv_type; /* 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | QuickTime TLV Length | QuickTime TLV Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime TLV Value ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ tlv_len = (payload[0] << 8) | payload[1]; tlv_type = (payload[2] << 8) | payload[3]; pdlen -= 4; if (tlv_len > pdlen) goto wrong_length; GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2], payload[3], tlv_len); payload += 4; payload_len -= 4; switch (tlv_type) { case TLV_sd: /* Session description */ if (!gst_rtp_quicktime_parse_sd (rtpxqtdepay, payload, tlv_len)) goto unknown_format; rtpxqtdepay->have_sd = TRUE; break; case TLV_qt: case TLV_ti: case TLV_ly: case TLV_vo: case TLV_mx: case TLV_tr: case TLV_tw: case TLV_th: case TLV_la: case TLV_rt: case TLV_gm: case TLV_oc: case TLV_cr: case TLV_du: case TLV_po: default: break; } pdlen -= tlv_len; payload += tlv_len; payload_len -= tlv_len; } payload += padding; payload_len -= padding; } if (l) { guint ssilen, ssipadded; gint padding; /* 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | RES | Sample-Specific Info Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime TLVs ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (payload_len <= 4) goto wrong_length; ssilen = (payload[2] << 8) | payload[3]; if (ssilen < 4) goto wrong_length; /* calc padding */ ssipadded = ssilen + 3; ssipadded -= ssipadded % 4; if (payload_len < ssipadded) goto wrong_length; padding = ssipadded - ssilen; GST_LOG_OBJECT (rtpxqtdepay, "len: %d, padding %d", ssilen, padding); payload += 4; payload_len -= 4; ssilen -= 4; /* parse TLV (type-length-value triplets */ while (ssilen > 3) { guint16 tlv_len, tlv_type; /* 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | QuickTime TLV Length | QuickTime TLV Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . QuickTime TLV Value ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ tlv_len = (payload[0] << 8) | payload[1]; tlv_type = (payload[2] << 8) | payload[3]; ssilen -= 4; if (tlv_len > ssilen) goto wrong_length; GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2], payload[3], tlv_len); payload += 4; payload_len -= 4; switch (tlv_type) { case TLV_sd: case TLV_qt: case TLV_ti: case TLV_ly: case TLV_vo: case TLV_mx: case TLV_tr: case TLV_tw: case TLV_th: case TLV_la: case TLV_rt: case TLV_gm: case TLV_oc: case TLV_cr: case TLV_du: case TLV_po: default: break; } ssilen -= tlv_len; payload += tlv_len; payload_len -= tlv_len; } payload += padding; payload_len -= padding; } rtpxqtdepay->previous_id = rtpxqtdepay->current_id; switch (pck) { case 1: { /* multiple samples per packet. */ outbuf = gst_buffer_new_and_alloc (payload_len); gst_buffer_fill (outbuf, 0, payload, payload_len); goto done; } case 2: { guint slen; /* multiple samples per packet. * 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |S| Reserved | Sample Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Sample Timestamp | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . Sample Data ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |S| Reserved | Sample Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Sample Timestamp | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . Sample Data ... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * . ...... . * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ while (payload_len > 8) { s = (payload[0] & 0x80) != 0; /* contains sync sample */ slen = (payload[2] << 8) | payload[3]; /* timestamp = * (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) | * payload[7]; */ payload += 8; payload_len -= 8; if (slen > payload_len) slen = payload_len; outbuf = gst_buffer_new_and_alloc (slen); gst_buffer_fill (outbuf, 0, payload, slen); if (!s) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); gst_rtp_base_depayload_push (depayload, outbuf); /* aligned on 32 bit boundary */ slen = GST_ROUND_UP_4 (slen); payload += slen; payload_len -= slen; } break; } case 3: { /* one sample per packet, use adapter to combine based on marker bit. */ outbuf = gst_buffer_new_and_alloc (payload_len); gst_buffer_fill (outbuf, 0, payload, payload_len); gst_adapter_push (rtpxqtdepay->adapter, outbuf); if (!m) goto done; avail = gst_adapter_available (rtpxqtdepay->adapter); outbuf = gst_adapter_take_buffer (rtpxqtdepay->adapter, avail); GST_DEBUG_OBJECT (rtpxqtdepay, "gst_rtp_xqt_depay_chain: pushing buffer of size %u", avail); goto done; } } } done: gst_rtp_buffer_unmap (&rtp); return outbuf; bad_packet: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("Packet did not validate."), (NULL)); goto done; } need_resync: { GST_DEBUG_OBJECT (rtpxqtdepay, "waiting for marker"); goto done; } wrong_version: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("Unknown payload version."), (NULL)); goto done; } pck_reserved: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("PCK reserved 0."), (NULL)); goto done; } wrong_length: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("Wrong payload length."), (NULL)); goto done; } unknown_format: { GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE, ("Unknown payload format."), (NULL)); goto done; } }
void AudioSourceProviderGStreamer::clearAdapters() { WTF::GMutexLocker<GMutex> lock(m_adapterMutex); gst_adapter_clear(m_frontLeftAdapter); gst_adapter_clear(m_frontRightAdapter); }
static void bp_vis_pcm_handoff (GstElement *sink, GstBuffer *buffer, GstPad *pad, gpointer userdata) { BansheePlayer *player = (BansheePlayer*)userdata; GstStructure *structure; gint channels, wanted_size; gfloat *data; BansheePlayerVisDataCallback vis_data_cb; g_return_if_fail (IS_BANSHEE_PLAYER (player)); vis_data_cb = player->vis_data_cb; if (vis_data_cb == NULL) { return; } if (player->vis_thawing) { // Flush our buffers out. gst_adapter_clear (player->vis_buffer); memset (player->vis_fft_sample_buffer, 0, sizeof(gfloat) * SLICE_SIZE); player->vis_thawing = FALSE; } structure = gst_caps_get_structure (gst_buffer_get_caps (buffer), 0); gst_structure_get_int (structure, "channels", &channels); wanted_size = channels * SLICE_SIZE * sizeof (gfloat); gst_adapter_push (player->vis_buffer, gst_buffer_copy (buffer)); while ((data = (gfloat *)gst_adapter_peek (player->vis_buffer, wanted_size)) != NULL) { gfloat *deinterlaced = g_malloc (wanted_size); gfloat *specbuf = g_new (gfloat, SLICE_SIZE * 2); gint i, j; memcpy (specbuf, player->vis_fft_sample_buffer, SLICE_SIZE * sizeof(gfloat)); for (i = 0; i < SLICE_SIZE; i++) { gfloat avg = 0.0f; for (j = 0; j < channels; j++) { gfloat sample = data[i * channels + j]; deinterlaced[j * SLICE_SIZE + i] = sample; avg += sample; } avg /= channels; specbuf[i + SLICE_SIZE] = avg; } memcpy (player->vis_fft_sample_buffer, &specbuf[SLICE_SIZE], SLICE_SIZE * sizeof(gfloat)); gst_fft_f32_window (player->vis_fft, specbuf, GST_FFT_WINDOW_HAMMING); gst_fft_f32_fft (player->vis_fft, specbuf, player->vis_fft_buffer); for (i = 0; i < SLICE_SIZE; i++) { gfloat val; GstFFTF32Complex cplx = player->vis_fft_buffer[i]; val = cplx.r * cplx.r + cplx.i * cplx.i; val /= SLICE_SIZE * SLICE_SIZE; val = 10.0f * log10f(val); val = (val + 60.0f) / 60.0f; if (val < 0.0f) val = 0.0f; specbuf[i] = val; } vis_data_cb (player, channels, SLICE_SIZE, deinterlaced, SLICE_SIZE, specbuf); g_free (deinterlaced); g_free (specbuf); gst_adapter_flush (player->vis_buffer, wanted_size); } }
static gboolean gst_type_find_element_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = FALSE; GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (parent); GST_DEBUG_OBJECT (typefind, "got %s event in mode %d", GST_EVENT_TYPE_NAME (event), typefind->mode); switch (typefind->mode) { case MODE_TYPEFIND: switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; /* Parse and push out our caps and data */ gst_event_parse_caps (event, &caps); res = gst_type_find_element_setcaps (typefind, caps); gst_event_unref (event); break; } case GST_EVENT_GAP: { GST_FIXME_OBJECT (typefind, "GAP events during typefinding not handled properly"); /* FIXME: These would need to be inserted in the stream at * the right position between buffers, but we combine all * buffers with a GstAdapter. Drop the GAP event for now, * which will only cause an implicit GAP between buffers. */ gst_event_unref (event); res = TRUE; break; } case GST_EVENT_EOS: { GST_INFO_OBJECT (typefind, "Got EOS and no type found yet"); gst_type_find_element_chain_do_typefinding (typefind, FALSE, TRUE); res = gst_pad_push_event (typefind->src, event); break; } case GST_EVENT_FLUSH_STOP:{ GList *l; GST_OBJECT_LOCK (typefind); for (l = typefind->cached_events; l; l = l->next) { if (GST_EVENT_IS_STICKY (l->data) && GST_EVENT_TYPE (l->data) != GST_EVENT_SEGMENT && GST_EVENT_TYPE (l->data) != GST_EVENT_EOS) { gst_pad_store_sticky_event (typefind->src, l->data); } gst_event_unref (l->data); } g_list_free (typefind->cached_events); typefind->cached_events = NULL; gst_adapter_clear (typefind->adapter); GST_OBJECT_UNLOCK (typefind); /* fall through */ } case GST_EVENT_FLUSH_START: res = gst_pad_push_event (typefind->src, event); break; default: /* Forward events that would happen before the caps event * directly instead of storing them. There's no reason not * to send them directly and we should only store events * for later sending that would need to come after the caps * event */ if (GST_EVENT_TYPE (event) < GST_EVENT_CAPS) { res = gst_pad_push_event (typefind->src, event); } else { GST_DEBUG_OBJECT (typefind, "Saving %s event to send later", GST_EVENT_TYPE_NAME (event)); GST_OBJECT_LOCK (typefind); typefind->cached_events = g_list_append (typefind->cached_events, event); GST_OBJECT_UNLOCK (typefind); res = TRUE; } break; } break; case MODE_NORMAL: res = gst_pad_push_event (typefind->src, event); break; case MODE_ERROR: break; default: g_assert_not_reached (); } return res; }
static GstFlowReturn gst_rtp_g723_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buf) { GstFlowReturn ret = GST_FLOW_OK; GstMapInfo map; guint8 HDR; GstRTPG723Pay *pay; GstClockTime packet_dur, timestamp; guint payload_len, packet_len; pay = GST_RTP_G723_PAY (payload); gst_buffer_map (buf, &map, GST_MAP_READ); timestamp = GST_BUFFER_PTS (buf); if (GST_BUFFER_IS_DISCONT (buf)) { /* flush everything on discont */ gst_adapter_clear (pay->adapter); pay->timestamp = GST_CLOCK_TIME_NONE; pay->duration = 0; pay->discont = TRUE; } /* should be one of these sizes */ if (map.size != 4 && map.size != 20 && map.size != 24) goto invalid_size; /* check size by looking at the header bits */ HDR = map.data[0] & 0x3; if (size_tab[HDR] != map.size) goto wrong_size; /* calculate packet size and duration */ payload_len = gst_adapter_available (pay->adapter) + map.size; packet_dur = pay->duration + G723_FRAME_DURATION; packet_len = gst_rtp_buffer_calc_packet_len (payload_len, 0, 0); if (gst_rtp_base_payload_is_filled (payload, packet_len, packet_dur)) { /* size or duration would overflow the packet, flush the queued data */ ret = gst_rtp_g723_pay_flush (pay); } /* update timestamp, we keep the timestamp for the first packet in the adapter * but are able to calculate it from next packets. */ if (timestamp != GST_CLOCK_TIME_NONE && pay->timestamp == GST_CLOCK_TIME_NONE) { if (timestamp > pay->duration) pay->timestamp = timestamp - pay->duration; else pay->timestamp = 0; } gst_buffer_unmap (buf, &map); /* add packet to the queue */ gst_adapter_push (pay->adapter, buf); pay->duration = packet_dur; /* check if we can flush now */ if (pay->duration >= payload->min_ptime) { ret = gst_rtp_g723_pay_flush (pay); } return ret; /* WARNINGS */ invalid_size: { GST_ELEMENT_WARNING (pay, STREAM, WRONG_TYPE, ("Invalid input buffer size"), ("Input size should be 4, 20 or 24, got %" G_GSIZE_FORMAT, map.size)); gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); return GST_FLOW_OK; } wrong_size: { GST_ELEMENT_WARNING (pay, STREAM, WRONG_TYPE, ("Wrong input buffer size"), ("Expected input buffer size %u but got %" G_GSIZE_FORMAT, size_tab[HDR], map.size)); gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); return GST_FLOW_OK; } }
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 gst_rtp_j2k_depay_flush_tile (GstRTPBaseDepayload * depayload) { GstRtpJ2KDepay *rtpj2kdepay; guint avail, mh_id; GList *packets, *walk; guint8 end[2]; GstFlowReturn ret = GST_FLOW_OK; GstMapInfo map; GstBuffer *buf; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); /* flush pending PU */ gst_rtp_j2k_depay_flush_pu (depayload); /* take all available buffers */ avail = gst_adapter_available (rtpj2kdepay->t_adapter); if (avail == 0) goto done; mh_id = rtpj2kdepay->last_mh_id; GST_DEBUG_OBJECT (rtpj2kdepay, "flushing tile of size %u", avail); if (gst_adapter_available (rtpj2kdepay->f_adapter) == 0) { GstBuffer *mheader; /* we need a header now */ if ((mheader = rtpj2kdepay->MH[mh_id]) == NULL) goto waiting_header; /* push header in the adapter */ GST_DEBUG_OBJECT (rtpj2kdepay, "pushing header %u", mh_id); gst_adapter_push (rtpj2kdepay->f_adapter, gst_buffer_ref (mheader)); } /* check for last bytes */ gst_adapter_copy (rtpj2kdepay->t_adapter, end, avail - 2, 2); /* now append the tile packets to the frame */ packets = gst_adapter_take_list (rtpj2kdepay->t_adapter, avail); for (walk = packets; walk; walk = g_list_next (walk)) { buf = GST_BUFFER_CAST (walk->data); if (walk == packets) { /* first buffer should contain the SOT */ gst_buffer_map (buf, &map, GST_MAP_READ); if (map.size < 12) goto invalid_tile; if (map.data[0] == 0xff && map.data[1] == J2K_MARKER_SOT) { guint Psot, nPsot; if (end[0] == 0xff && end[1] == J2K_MARKER_EOC) nPsot = avail - 2; else nPsot = avail; Psot = GST_READ_UINT32_BE (&map.data[6]); if (Psot != nPsot && Psot != 0) { /* Psot must match the size of the tile */ GST_DEBUG_OBJECT (rtpj2kdepay, "set Psot from %u to %u", Psot, nPsot); gst_buffer_unmap (buf, &map); buf = gst_buffer_make_writable (buf); gst_buffer_map (buf, &map, GST_MAP_WRITE); GST_WRITE_UINT32_BE (&map.data[6], nPsot); } } gst_buffer_unmap (buf, &map); } GST_DEBUG_OBJECT (rtpj2kdepay, "append pu packet of size %" G_GSIZE_FORMAT, gst_buffer_get_size (buf)); gst_adapter_push (rtpj2kdepay->f_adapter, buf); } g_list_free (packets); done: rtpj2kdepay->last_tile = -1; return ret; /* errors */ waiting_header: { GST_DEBUG_OBJECT (rtpj2kdepay, "waiting for header %u", mh_id); gst_adapter_clear (rtpj2kdepay->t_adapter); rtpj2kdepay->last_tile = -1; return ret; } invalid_tile: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Invalid tile"), (NULL)); gst_buffer_unmap (buf, &map); gst_adapter_clear (rtpj2kdepay->t_adapter); rtpj2kdepay->last_tile = -1; return ret; } }
static GstFlowReturn gst_rtp_j2k_depay_flush_frame (GstRTPBaseDepayload * depayload) { GstRtpJ2KDepay *rtpj2kdepay; guint8 end[2]; guint avail; GstFlowReturn ret = GST_FLOW_OK; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); /* flush pending tile */ gst_rtp_j2k_depay_flush_tile (depayload); /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpj2kdepay->f_adapter); if (avail == 0) goto done; if (avail > 2) { GstBuffer *outbuf; /* take the last bytes of the JPEG 2000 data to see if there is an EOC * marker */ gst_adapter_copy (rtpj2kdepay->f_adapter, end, avail - 2, 2); if (end[0] != 0xff && end[1] != 0xd9) { end[0] = 0xff; end[1] = 0xd9; GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one"); /* no EOI marker, add one */ outbuf = gst_buffer_new_and_alloc (2); gst_buffer_fill (outbuf, 0, end, 2); gst_adapter_push (rtpj2kdepay->f_adapter, outbuf); avail += 2; } GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer of %u bytes", avail); outbuf = gst_adapter_take_buffer (rtpj2kdepay->f_adapter, avail); gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload), outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR)); ret = gst_rtp_base_depayload_push (depayload, outbuf); } else { GST_WARNING_OBJECT (rtpj2kdepay, "empty packet"); gst_adapter_clear (rtpj2kdepay->f_adapter); } /* we accept any mh_id now */ rtpj2kdepay->last_mh_id = -1; /* reset state */ rtpj2kdepay->next_frag = 0; rtpj2kdepay->have_sync = FALSE; done: /* we can't keep headers with mh_id of 0 */ store_mheader (rtpj2kdepay, 0, NULL); return ret; }
static GstFlowReturn gst_wavpack_parse_chain (GstPad * pad, GstBuffer * buf) { GstWavpackParse *wvparse = GST_WAVPACK_PARSE (GST_PAD_PARENT (pad)); GstFlowReturn ret = GST_FLOW_OK; WavpackHeader wph; const guint8 *tmp_buf; if (!wvparse->adapter) { wvparse->adapter = gst_adapter_new (); } if (GST_BUFFER_IS_DISCONT (buf)) { gst_adapter_clear (wvparse->adapter); wvparse->discont = TRUE; } gst_adapter_push (wvparse->adapter, buf); if (gst_adapter_available (wvparse->adapter) < sizeof (WavpackHeader)) return ret; if (!gst_wavpack_parse_resync_adapter (wvparse->adapter)) return ret; tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader)); gst_wavpack_read_header (&wph, (guint8 *) tmp_buf); while (gst_adapter_available (wvparse->adapter) >= wph.ckSize + 4 * 1 + 4) { GstBuffer *outbuf = gst_adapter_take_buffer (wvparse->adapter, wph.ckSize + 4 * 1 + 4); if (!outbuf) return GST_FLOW_ERROR; if (wvparse->srcpad == NULL) { if (!gst_wavpack_parse_create_src_pad (wvparse, outbuf, &wph)) { GST_ERROR_OBJECT (wvparse, "Failed to create src pad"); ret = GST_FLOW_ERROR; break; } } ret = gst_wavpack_parse_push_buffer (wvparse, outbuf, &wph); if (ret != GST_FLOW_OK) break; if (gst_adapter_available (wvparse->adapter) >= sizeof (WavpackHeader)) { tmp_buf = gst_adapter_peek (wvparse->adapter, sizeof (WavpackHeader)); if (!gst_wavpack_parse_resync_adapter (wvparse->adapter)) break; gst_wavpack_read_header (&wph, (guint8 *) tmp_buf); } } return ret; }
static void gst_rtp_j2k_depay_clear_pu (GstRtpJ2KDepay * rtpj2kdepay) { gst_adapter_clear (rtpj2kdepay->pu_adapter); rtpj2kdepay->have_sync = FALSE; }
static GstBuffer * gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstRTPBuffer * rtp) { GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay); GstBuffer *payload; guint8 *data; guint hdrsize; guint size; 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); /* At least one header and one vp8 byte */ if (G_UNLIKELY (size < 2)) goto too_small; data = gst_rtp_buffer_get_payload (rtp); if (G_UNLIKELY (!self->started)) { /* Check if this is the start of a VP8 frame, otherwise bail */ /* S=1 and PartID= 0 */ if ((data[0] & 0x17) != 0x10) goto done; self->started = TRUE; } hdrsize = 1; /* Check X optional header */ if ((data[0] & 0x80) != 0) { hdrsize++; /* Check I optional header */ if ((data[1] & 0x80) != 0) { if (G_UNLIKELY (size < 3)) goto too_small; hdrsize++; /* Check for 16 bits PictureID */ if ((data[2] & 0x80) != 0) hdrsize++; } /* Check L optional header */ if ((data[1] & 0x40) != 0) hdrsize++; /* Check T or K optional headers */ if ((data[1] & 0x20) != 0 || (data[1] & 0x10) != 0) hdrsize++; } 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); 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; guint8 header[10]; gst_adapter_copy (self->adapter, &header, 0, 10); out = gst_adapter_take_buffer (self->adapter, gst_adapter_available (self->adapter)); self->started = FALSE; /* mark keyframes */ out = gst_buffer_make_writable (out); if ((header[0] & 0x01)) { 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 { guint profile, width, height; GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT); profile = (header[0] & 0x0e) >> 1; width = GST_READ_UINT16_LE (header + 6) & 0x3fff; height = GST_READ_UINT16_LE (header + 8) & 0x3fff; if (G_UNLIKELY (self->last_width != width || self->last_height != height || self->last_profile != profile)) { gchar profile_str[3]; GstCaps *srccaps; snprintf (profile_str, 3, "%u", profile); srccaps = gst_caps_new_simple ("video/x-vp8", "framerate", GST_TYPE_FRACTION, 0, 1, "height", G_TYPE_INT, height, "width", G_TYPE_INT, width, "profile", G_TYPE_STRING, profile_str, NULL); gst_pad_set_caps (GST_RTP_BASE_DEPAYLOAD_SRCPAD (depay), srccaps); gst_caps_unref (srccaps); self->caps_sent = TRUE; self->last_width = width; self->last_height = height; self->last_profile = profile; } } 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 gst_vdp_mpeg_dec_chain (GstPad * pad, GstBuffer * buffer) { GstVdpMpegDec *mpeg_dec = GST_VDP_MPEG_DEC (gst_pad_get_parent (pad)); GstVdpMpegPacketizer packetizer; GstBuffer *buf; GstFlowReturn ret = GST_FLOW_OK; if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT))) { GST_DEBUG_OBJECT (mpeg_dec, "Received discont buffer"); gst_vdp_mpeg_dec_flush (mpeg_dec); } gst_vdp_mpeg_packetizer_init (&packetizer, buffer); while ((buf = gst_vdp_mpeg_packetizer_get_next_packet (&packetizer))) { GstBitReader b_reader = GST_BIT_READER_INIT_FROM_BUFFER (buf); guint32 sync_code; guint8 start_code; /* skip sync_code */ gst_bit_reader_get_bits_uint32 (&b_reader, &sync_code, 8 * 3); /* start_code */ gst_bit_reader_get_bits_uint8 (&b_reader, &start_code, 8); if (start_code >= MPEG_PACKET_SLICE_MIN && start_code <= MPEG_PACKET_SLICE_MAX) { GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_SLICE"); gst_buffer_ref (buf); gst_adapter_push (mpeg_dec->adapter, buf); mpeg_dec->vdp_info.slice_count++; } switch (start_code) { case MPEG_PACKET_PICTURE: GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_PICTURE"); if (!gst_vdp_mpeg_dec_parse_picture (mpeg_dec, buf)) goto done; break; case MPEG_PACKET_SEQUENCE: GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_SEQUENCE"); gst_vdp_mpeg_dec_parse_sequence (mpeg_dec, buf); break; case MPEG_PACKET_EXTENSION: { guint8 ext_code; GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXTENSION"); /* ext_code */ gst_bit_reader_get_bits_uint8 (&b_reader, &ext_code, 4); switch (ext_code) { case MPEG_PACKET_EXT_PICTURE_CODING: GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXT_PICTURE_CODING"); gst_vdp_mpeg_dec_parse_picture_coding (mpeg_dec, buf); break; case MPEG_PACKET_EXT_QUANT_MATRIX: GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_EXT_QUANT_MATRIX"); gst_vdp_mpeg_dec_parse_quant_matrix (mpeg_dec, buf); break; default: break; } break; } case MPEG_PACKET_GOP: GST_DEBUG_OBJECT (mpeg_dec, "MPEG_PACKET_GOP"); gst_vdp_mpeg_dec_parse_gop (mpeg_dec, buf); break; default: break; } gst_buffer_unref (buf); } if (mpeg_dec->state == GST_VDP_MPEG_DEC_NEED_SEQUENCE || mpeg_dec->state == GST_VDP_MPEG_DEC_NEED_GOP) { gst_adapter_clear (mpeg_dec->adapter); goto done; } if (mpeg_dec->vdp_info.slice_count > 0) ret = gst_vdp_mpeg_dec_decode (mpeg_dec, GST_BUFFER_TIMESTAMP (buffer), GST_BUFFER_SIZE (buffer)); done: gst_object_unref (mpeg_dec); return ret; }
static GstFlowReturn gst_vdp_mpeg_dec_decode (GstVdpMpegDec * mpeg_dec, GstClockTime timestamp, gint64 size) { VdpPictureInfoMPEG1Or2 *info; GstBuffer *buffer; GstBuffer *outbuf; VdpVideoSurface surface; GstVdpDevice *device; VdpBitstreamBuffer vbit[1]; VdpStatus status; info = &mpeg_dec->vdp_info; if (info->picture_coding_type != B_FRAME) { if (info->backward_reference != VDP_INVALID_HANDLE) { gst_buffer_ref (mpeg_dec->b_buffer); gst_vdp_mpeg_dec_push_video_buffer (mpeg_dec, GST_VDP_VIDEO_BUFFER (mpeg_dec->b_buffer)); } if (info->forward_reference != VDP_INVALID_HANDLE) { gst_buffer_unref (mpeg_dec->f_buffer); info->forward_reference = VDP_INVALID_HANDLE; } info->forward_reference = info->backward_reference; mpeg_dec->f_buffer = mpeg_dec->b_buffer; info->backward_reference = VDP_INVALID_HANDLE; } if (gst_vdp_mpeg_dec_alloc_buffer (mpeg_dec, &outbuf) != GST_FLOW_OK) { gst_adapter_clear (mpeg_dec->adapter); return GST_FLOW_ERROR; } device = GST_VDP_VIDEO_BUFFER (outbuf)->device; if (info->forward_reference != VDP_INVALID_HANDLE && info->picture_coding_type != I_FRAME) gst_vdp_video_buffer_add_reference (GST_VDP_VIDEO_BUFFER (outbuf), GST_VDP_VIDEO_BUFFER (mpeg_dec->f_buffer)); if (info->backward_reference != VDP_INVALID_HANDLE && info->picture_coding_type == B_FRAME) gst_vdp_video_buffer_add_reference (GST_VDP_VIDEO_BUFFER (outbuf), GST_VDP_VIDEO_BUFFER (mpeg_dec->b_buffer)); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = mpeg_dec->duration; GST_BUFFER_OFFSET (outbuf) = mpeg_dec->frame_nr; GST_BUFFER_SIZE (outbuf) = size; if (info->picture_coding_type == I_FRAME) GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); else GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); if (info->top_field_first) GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_TFF); else GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_TFF); buffer = gst_adapter_take_buffer (mpeg_dec->adapter, gst_adapter_available (mpeg_dec->adapter)); surface = GST_VDP_VIDEO_BUFFER (outbuf)->surface; vbit[0].struct_version = VDP_BITSTREAM_BUFFER_VERSION; vbit[0].bitstream = GST_BUFFER_DATA (buffer); vbit[0].bitstream_bytes = GST_BUFFER_SIZE (buffer); status = device->vdp_decoder_render (mpeg_dec->decoder, surface, (VdpPictureInfo *) info, 1, vbit); gst_buffer_unref (buffer); info->slice_count = 0; if (status != VDP_STATUS_OK) { GST_ELEMENT_ERROR (mpeg_dec, RESOURCE, READ, ("Could not decode"), ("Error returned from vdpau was: %s", device->vdp_get_error_string (status))); gst_buffer_unref (GST_BUFFER (outbuf)); return GST_FLOW_ERROR; } if (info->picture_coding_type == B_FRAME) { gst_vdp_mpeg_dec_push_video_buffer (mpeg_dec, GST_VDP_VIDEO_BUFFER (outbuf)); } else { info->backward_reference = surface; mpeg_dec->b_buffer = GST_BUFFER (outbuf); } return GST_FLOW_OK; }
static gboolean gst_jpeg_parse_sink_event (GstPad * pad, GstEvent * event) { GstJpegParse *parse; gboolean res = TRUE; parse = GST_JPEG_PARSE (gst_pad_get_parent (pad)); GST_DEBUG_OBJECT (parse, "event : %s", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); res = gst_jpeg_parse_sink_setcaps (pad, caps); gst_event_unref (event); break; } case GST_EVENT_FLUSH_STOP: parse->priv->next_ts = GST_CLOCK_TIME_NONE; parse->priv->duration = GST_CLOCK_TIME_NONE; parse->priv->last_offset = 0; parse->priv->last_entropy_len = 0; parse->priv->last_resync = FALSE; gst_adapter_clear (parse->priv->adapter); break; case GST_EVENT_EOS:{ /* Push the remaining data, even though it's incomplete */ guint available = gst_adapter_available (parse->priv->adapter); if (available > 0) gst_jpeg_parse_push_buffer (parse, available); res = gst_pad_push_event (parse->priv->srcpad, event); break; } case GST_EVENT_SEGMENT: /* Discard any data in the adapter. There should have been an EOS before * to flush it. */ gst_adapter_clear (parse->priv->adapter); res = gst_pad_push_event (parse->priv->srcpad, event); parse->priv->new_segment = TRUE; break; case GST_EVENT_TAG:{ if (!parse->priv->new_segment) res = gst_pad_event_default (pad, event); else { GstTagList *taglist = NULL; gst_event_parse_tag (event, &taglist); /* Hold on to the tags till the srcpad caps are definitely set */ gst_tag_list_insert (get_tag_list (parse), taglist, GST_TAG_MERGE_REPLACE); GST_DEBUG ("collected tags: %" GST_PTR_FORMAT, parse->priv->tags); gst_event_unref (event); } break; } default: res = gst_pad_event_default (pad, event); break; } gst_object_unref (parse); return res; }
static GstFlowReturn gst_siren_enc_chain (GstPad * pad, GstBuffer * buf) { GstSirenEnc *enc; GstFlowReturn ret = GST_FLOW_OK; GstBuffer *out_buf; guint8 *in_data, *out_data; guint8 *to_free = NULL; guint i, size, num_frames; gint out_size, in_size; gint encode_ret; gboolean discont; GstClockTime timestamp; guint64 distance; GstCaps *outcaps; enc = GST_SIREN_ENC (GST_PAD_PARENT (pad)); discont = GST_BUFFER_IS_DISCONT (buf); if (discont) { GST_DEBUG_OBJECT (enc, "received DISCONT, flush adapter"); gst_adapter_clear (enc->adapter); enc->discont = TRUE; } gst_adapter_push (enc->adapter, buf); size = gst_adapter_available (enc->adapter); GST_LOG_OBJECT (enc, "Received buffer of size %d with adapter of size : %d", GST_BUFFER_SIZE (buf), size); /* we need to process 640 input bytes to produce 40 output bytes */ /* calculate the amount of frames we will handle */ num_frames = size / 640; /* no frames, wait some more */ if (num_frames == 0) goto done; /* this is the input/output size */ in_size = num_frames * 640; out_size = num_frames * 40; GST_LOG_OBJECT (enc, "we have %u frames, %u in, %u out", num_frames, in_size, out_size); /* set output caps when needed */ if ((outcaps = GST_PAD_CAPS (enc->srcpad)) == NULL) { outcaps = gst_static_pad_template_get_caps (&srctemplate); gst_pad_set_caps (enc->srcpad, outcaps); gst_caps_unref (outcaps); } /* get a buffer */ ret = gst_pad_alloc_buffer_and_set_caps (enc->srcpad, -1, out_size, outcaps, &out_buf); if (ret != GST_FLOW_OK) goto alloc_failed; /* get the timestamp for the output buffer */ timestamp = gst_adapter_prev_timestamp (enc->adapter, &distance); /* add the amount of time taken by the distance */ if (timestamp != -1) timestamp += gst_util_uint64_scale_int (distance / 2, GST_SECOND, 16000); GST_LOG_OBJECT (enc, "timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT, GST_TIME_ARGS (timestamp), distance); /* get the input data for all the frames */ to_free = in_data = gst_adapter_take (enc->adapter, in_size); out_data = GST_BUFFER_DATA (out_buf); for (i = 0; i < num_frames; i++) { GST_LOG_OBJECT (enc, "Encoding frame %u/%u", i, num_frames); /* encode 640 input bytes to 40 output bytes */ encode_ret = Siren7_EncodeFrame (enc->encoder, in_data, out_data); if (encode_ret != 0) goto encode_error; /* move to next frame */ out_data += 40; in_data += 640; } GST_LOG_OBJECT (enc, "Finished encoding"); /* mark discont */ if (enc->discont) { GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT); enc->discont = FALSE; } GST_BUFFER_TIMESTAMP (out_buf) = timestamp; GST_BUFFER_DURATION (out_buf) = num_frames * FRAME_DURATION; ret = gst_pad_push (enc->srcpad, out_buf); done: if (to_free) g_free (to_free); return ret; /* ERRORS */ alloc_failed: { GST_DEBUG_OBJECT (enc, "failed to pad_alloc buffer: %d (%s)", ret, gst_flow_get_name (ret)); goto done; } encode_error: { GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL), ("Error encoding frame: %d", encode_ret)); ret = GST_FLOW_ERROR; gst_buffer_unref (out_buf); goto done; } }
static GstFlowReturn gst_gdp_depay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstGDPDepay *this; GstFlowReturn ret = GST_FLOW_OK; GstCaps *caps; GstBuffer *buf; GstEvent *event; guint available; this = GST_GDP_DEPAY (parent); /* On DISCONT, get rid of accumulated data. We assume a buffer after the * DISCONT contains (part of) a new valid header, if not we error because we * lost sync */ if (GST_BUFFER_IS_DISCONT (buffer)) { gst_adapter_clear (this->adapter); this->state = GST_GDP_DEPAY_STATE_HEADER; } gst_adapter_push (this->adapter, buffer); while (TRUE) { switch (this->state) { case GST_GDP_DEPAY_STATE_HEADER: { guint8 *header; /* collect a complete header, validate and store the header. Figure out * the payload length and switch to the PAYLOAD state */ available = gst_adapter_available (this->adapter); if (available < GST_DP_HEADER_LENGTH) goto done; GST_LOG_OBJECT (this, "reading GDP header from adapter"); header = gst_adapter_take (this->adapter, GST_DP_HEADER_LENGTH); if (!gst_dp_validate_header (GST_DP_HEADER_LENGTH, header)) { g_free (header); goto header_validate_error; } /* store types and payload length. Also store the header, which we need * to make the payload. */ this->payload_length = gst_dp_header_payload_length (header); this->payload_type = gst_dp_header_payload_type (header); /* free previous header and store new one. */ g_free (this->header); this->header = header; GST_LOG_OBJECT (this, "read GDP header, payload size %d, payload type %d, switching to state PAYLOAD", this->payload_length, this->payload_type); this->state = GST_GDP_DEPAY_STATE_PAYLOAD; break; } case GST_GDP_DEPAY_STATE_PAYLOAD: { /* in this state we wait for all the payload data to be available in the * adapter. Then we switch to the state where we actually process the * payload. */ available = gst_adapter_available (this->adapter); if (available < this->payload_length) goto done; /* change state based on type */ if (this->payload_type == GST_DP_PAYLOAD_BUFFER) { GST_LOG_OBJECT (this, "switching to state BUFFER"); this->state = GST_GDP_DEPAY_STATE_BUFFER; } else if (this->payload_type == GST_DP_PAYLOAD_CAPS) { GST_LOG_OBJECT (this, "switching to state CAPS"); this->state = GST_GDP_DEPAY_STATE_CAPS; } else if (this->payload_type >= GST_DP_PAYLOAD_EVENT_NONE) { GST_LOG_OBJECT (this, "switching to state EVENT"); this->state = GST_GDP_DEPAY_STATE_EVENT; } else { goto wrong_type; } if (this->payload_length) { const guint8 *data; gboolean res; data = gst_adapter_map (this->adapter, this->payload_length); res = gst_dp_validate_payload (GST_DP_HEADER_LENGTH, this->header, data); gst_adapter_unmap (this->adapter); if (!res) goto payload_validate_error; } break; } case GST_GDP_DEPAY_STATE_BUFFER: { /* if we receive a buffer without caps first, we error out */ if (!this->caps) goto no_caps; GST_LOG_OBJECT (this, "reading GDP buffer from adapter"); buf = gst_dp_buffer_from_header (GST_DP_HEADER_LENGTH, this->header); if (!buf) goto buffer_failed; /* now take the payload if there is any */ if (this->payload_length > 0) { GstMapInfo map; gst_buffer_map (buf, &map, GST_MAP_WRITE); gst_adapter_copy (this->adapter, map.data, 0, this->payload_length); gst_buffer_unmap (buf, &map); gst_adapter_flush (this->adapter, this->payload_length); } /* set caps and push */ GST_LOG_OBJECT (this, "deserialized buffer %p, pushing, timestamp %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT ", size %" G_GSIZE_FORMAT ", flags 0x%x", buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf), gst_buffer_get_size (buf), GST_BUFFER_FLAGS (buf)); ret = gst_pad_push (this->srcpad, buf); if (ret != GST_FLOW_OK) goto push_error; GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } case GST_GDP_DEPAY_STATE_CAPS: { guint8 *payload; /* take the payload of the caps */ GST_LOG_OBJECT (this, "reading GDP caps from adapter"); payload = gst_adapter_take (this->adapter, this->payload_length); caps = gst_dp_caps_from_packet (GST_DP_HEADER_LENGTH, this->header, payload); g_free (payload); if (!caps) goto caps_failed; GST_DEBUG_OBJECT (this, "deserialized caps %" GST_PTR_FORMAT, caps); gst_caps_replace (&(this->caps), caps); gst_pad_set_caps (this->srcpad, caps); /* drop the creation ref we still have */ gst_caps_unref (caps); GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } case GST_GDP_DEPAY_STATE_EVENT: { guint8 *payload; GST_LOG_OBJECT (this, "reading GDP event from adapter"); /* adapter doesn't like 0 length payload */ if (this->payload_length > 0) payload = gst_adapter_take (this->adapter, this->payload_length); else payload = NULL; event = gst_dp_event_from_packet (GST_DP_HEADER_LENGTH, this->header, payload); g_free (payload); if (!event) goto event_failed; GST_DEBUG_OBJECT (this, "deserialized event %p of type %s, pushing", event, gst_event_type_get_name (event->type)); gst_pad_push_event (this->srcpad, event); GST_LOG_OBJECT (this, "switching to state HEADER"); this->state = GST_GDP_DEPAY_STATE_HEADER; break; } } } done: return ret; /* ERRORS */ header_validate_error: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet header does not validate")); ret = GST_FLOW_ERROR; goto done; } payload_validate_error: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet payload does not validate")); ret = GST_FLOW_ERROR; goto done; } wrong_type: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("GDP packet header is of wrong type")); ret = GST_FLOW_ERROR; goto done; } no_caps: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("Received a buffer without first receiving caps")); ret = GST_FLOW_NOT_NEGOTIATED; goto done; } buffer_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create buffer from GDP packet")); ret = GST_FLOW_ERROR; goto done; } push_error: { GST_WARNING_OBJECT (this, "pushing depayloaded buffer returned %d", ret); goto done; } caps_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create caps from GDP packet")); ret = GST_FLOW_ERROR; goto done; } event_failed: { GST_ELEMENT_ERROR (this, STREAM, DECODE, (NULL), ("could not create event from GDP packet")); ret = GST_FLOW_ERROR; goto done; } }
static void gst_rtp_mp4v_pay_empty (GstRtpMP4VPay * rtpmp4vpay) { gst_adapter_clear (rtpmp4vpay->adapter); }
static GstFlowReturn gst_multipart_demux_chain (GstPad * pad, GstBuffer * buf) { GstMultipartDemux *multipart; GstAdapter *adapter; GstClockTime timestamp; gint size = 1; GstFlowReturn res; multipart = GST_MULTIPART_DEMUX (gst_pad_get_parent (pad)); adapter = multipart->adapter; res = GST_FLOW_OK; timestamp = GST_BUFFER_TIMESTAMP (buf); if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (adapter); } gst_adapter_push (adapter, buf); while (gst_adapter_available (adapter) > 0) { GstMultipartPad *srcpad; GstBuffer *outbuf; gboolean created; gint datalen; if (G_UNLIKELY (!multipart->header_completed)) { if ((size = multipart_parse_header (multipart)) < 0) { goto nodata; } else { gst_adapter_flush (adapter, size); multipart->header_completed = TRUE; } } if ((size = multipart_find_boundary (multipart, &datalen)) < 0) { goto nodata; } /* Invalidate header info */ multipart->header_completed = FALSE; multipart->content_length = -1; if (G_UNLIKELY (datalen <= 0)) { GST_DEBUG_OBJECT (multipart, "skipping empty content."); gst_adapter_flush (adapter, size - datalen); } else { srcpad = gst_multipart_find_pad_by_mime (multipart, multipart->mime_type, &created); outbuf = gst_adapter_take_buffer (adapter, datalen); gst_adapter_flush (adapter, size - datalen); gst_buffer_set_caps (outbuf, GST_PAD_CAPS (srcpad->pad)); if (created) { GstTagList *tags; /* Push new segment, first buffer has 0 timestamp */ gst_pad_push_event (srcpad->pad, gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME, 0, -1, 0)); tags = gst_tag_list_new_full (GST_TAG_CONTAINER_FORMAT, "Multipart", NULL); gst_pad_push_event (srcpad->pad, gst_event_new_tag (tags)); GST_BUFFER_TIMESTAMP (outbuf) = 0; } else { GST_BUFFER_TIMESTAMP (outbuf) = timestamp; } GST_DEBUG_OBJECT (multipart, "pushing buffer with timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); GST_DEBUG_OBJECT (multipart, "buffer has caps %" GST_PTR_FORMAT, GST_BUFFER_CAPS (outbuf)); res = gst_pad_push (srcpad->pad, outbuf); res = gst_multipart_combine_flows (multipart, srcpad, res); if (res != GST_FLOW_OK) break; } } nodata: gst_object_unref (multipart); if (G_UNLIKELY (size == MULTIPART_DATA_ERROR)) return GST_FLOW_ERROR; if (G_UNLIKELY (size == MULTIPART_DATA_EOS)) return GST_FLOW_UNEXPECTED; return res; }
static GstBuffer * gst_rtp_j2k_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpJ2KDepay *rtpj2kdepay; GstBuffer *outbuf; guint8 *payload; guint frag_offset; rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload); /* flush everything on discont for now */ if (GST_BUFFER_IS_DISCONT (buf)) { GST_DEBUG_OBJECT (rtpj2kdepay, "DISCONT, flushing data"); gst_adapter_clear (rtpj2kdepay->adapter); rtpj2kdepay->need_header = TRUE; } if (gst_rtp_buffer_get_payload_len (buf) < 8) goto empty_packet; payload = gst_rtp_buffer_get_payload (buf); /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |tp |MHF|mh_id|T| priority | tile number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |reserved | fragment offset | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ frag_offset = (payload[5] << 16) | (payload[6] << 8) | payload[7]; GST_DEBUG_OBJECT (rtpj2kdepay, "frag %u", frag_offset); if (rtpj2kdepay->need_header) { if (frag_offset != 0) goto waiting_header; rtpj2kdepay->need_header = FALSE; } /* take JPEG 2000 data, push in the adapter */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 8, -1); gst_adapter_push (rtpj2kdepay->adapter, outbuf); outbuf = NULL; if (gst_rtp_buffer_get_marker (buf)) { guint avail; guint8 end[2]; guint8 *data; /* last buffer take all data out of the adapter */ avail = gst_adapter_available (rtpj2kdepay->adapter); GST_DEBUG_OBJECT (rtpj2kdepay, "marker set, last buffer"); /* take the last bytes of the JPEG 2000 data to see if there is an EOC * marker */ gst_adapter_copy (rtpj2kdepay->adapter, end, avail - 2, 2); if (end[0] != 0xff && end[1] != 0xd9) { GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one"); /* no EOI marker, add one */ outbuf = gst_buffer_new_and_alloc (2); data = GST_BUFFER_DATA (outbuf); data[0] = 0xff; data[1] = 0xd9; gst_adapter_push (rtpj2kdepay->adapter, outbuf); avail += 2; } outbuf = gst_adapter_take_buffer (rtpj2kdepay->adapter, avail); GST_DEBUG_OBJECT (rtpj2kdepay, "returning %u bytes", avail); } return outbuf; /* ERRORS */ empty_packet: { GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Empty Payload."), (NULL)); return NULL; } waiting_header: { GST_DEBUG_OBJECT (rtpj2kdepay, "we are waiting for a header"); return NULL; } }
static gboolean gst_type_find_element_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = FALSE; GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (parent); GST_DEBUG_OBJECT (typefind, "got %s event in mode %d", GST_EVENT_TYPE_NAME (event), typefind->mode); switch (typefind->mode) { case MODE_TYPEFIND: switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; /* first pass the caps event downstream */ res = gst_pad_push_event (typefind->src, gst_event_ref (event)); /* then parse and push out our data */ gst_event_parse_caps (event, &caps); res = gst_type_find_element_setcaps (typefind, caps); gst_event_unref (event); break; } case GST_EVENT_EOS: { GST_INFO_OBJECT (typefind, "Got EOS and no type found yet"); gst_type_find_element_chain_do_typefinding (typefind, FALSE); res = gst_pad_push_event (typefind->src, event); break; } case GST_EVENT_FLUSH_STOP: GST_OBJECT_LOCK (typefind); g_list_foreach (typefind->cached_events, (GFunc) gst_mini_object_unref, NULL); g_list_free (typefind->cached_events); typefind->cached_events = NULL; gst_adapter_clear (typefind->adapter); GST_OBJECT_UNLOCK (typefind); /* fall through */ case GST_EVENT_FLUSH_START: res = gst_pad_push_event (typefind->src, event); break; default: GST_DEBUG_OBJECT (typefind, "Saving %s event to send later", GST_EVENT_TYPE_NAME (event)); GST_OBJECT_LOCK (typefind); typefind->cached_events = g_list_append (typefind->cached_events, event); GST_OBJECT_UNLOCK (typefind); res = TRUE; break; } break; case MODE_NORMAL: res = gst_pad_push_event (typefind->src, event); break; case MODE_ERROR: break; default: g_assert_not_reached (); } return res; }
static GstFlowReturn gst_multipart_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstMultipartDemux *multipart; GstAdapter *adapter; gint size = 1; GstFlowReturn res; multipart = GST_MULTIPART_DEMUX (parent); adapter = multipart->adapter; res = GST_FLOW_OK; if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) { GSList *l; for (l = multipart->srcpads; l != NULL; l = l->next) { GstMultipartPad *srcpad = l->data; srcpad->discont = TRUE; } gst_adapter_clear (adapter); } gst_adapter_push (adapter, buf); while (gst_adapter_available (adapter) > 0) { GstMultipartPad *srcpad; GstBuffer *outbuf; gboolean created; gint datalen; if (G_UNLIKELY (!multipart->header_completed)) { if ((size = multipart_parse_header (multipart)) < 0) { goto nodata; } else { gst_adapter_flush (adapter, size); multipart->header_completed = TRUE; } } if ((size = multipart_find_boundary (multipart, &datalen)) < 0) { goto nodata; } /* Invalidate header info */ multipart->header_completed = FALSE; multipart->content_length = -1; if (G_UNLIKELY (datalen <= 0)) { GST_DEBUG_OBJECT (multipart, "skipping empty content."); gst_adapter_flush (adapter, size - datalen); } else if (G_UNLIKELY (!multipart->mime_type)) { GST_DEBUG_OBJECT (multipart, "content has no MIME type."); gst_adapter_flush (adapter, size - datalen); } else { GstClockTime ts; srcpad = gst_multipart_find_pad_by_mime (multipart, multipart->mime_type, &created); ts = gst_adapter_prev_pts (adapter, NULL); outbuf = gst_adapter_take_buffer (adapter, datalen); gst_adapter_flush (adapter, size - datalen); if (created) { GstTagList *tags; GstSegment segment; gst_segment_init (&segment, GST_FORMAT_TIME); /* Push new segment, first buffer has 0 timestamp */ gst_pad_push_event (srcpad->pad, gst_event_new_segment (&segment)); tags = gst_tag_list_new (GST_TAG_CONTAINER_FORMAT, "Multipart", NULL); gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL); gst_pad_push_event (srcpad->pad, gst_event_new_tag (tags)); } outbuf = gst_buffer_make_writable (outbuf); if (srcpad->last_ts == GST_CLOCK_TIME_NONE || srcpad->last_ts != ts) { GST_BUFFER_TIMESTAMP (outbuf) = ts; srcpad->last_ts = ts; } else { GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; } if (srcpad->discont) { GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); srcpad->discont = FALSE; } else { GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DISCONT); } GST_DEBUG_OBJECT (multipart, "pushing buffer with timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); res = gst_pad_push (srcpad->pad, outbuf); res = gst_multipart_combine_flows (multipart, srcpad, res); if (res != GST_FLOW_OK) break; } } nodata: if (G_UNLIKELY (size == MULTIPART_DATA_ERROR)) return GST_FLOW_ERROR; if (G_UNLIKELY (size == MULTIPART_DATA_EOS)) return GST_FLOW_EOS; return res; }
static GstFlowReturn gst_monoscope_chain (GstPad * pad, GstObject * parent, GstBuffer * inbuf) { GstFlowReturn flow_ret = GST_FLOW_OK; GstMonoscope *monoscope; monoscope = GST_MONOSCOPE (parent); if (monoscope->rate == 0) { gst_buffer_unref (inbuf); flow_ret = GST_FLOW_NOT_NEGOTIATED; goto out; } /* Make sure have an output format */ flow_ret = ensure_negotiated (monoscope); if (flow_ret != GST_FLOW_OK) { gst_buffer_unref (inbuf); goto out; } /* don't try to combine samples from discont buffer */ if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (monoscope->adapter); monoscope->next_ts = GST_CLOCK_TIME_NONE; } /* Match timestamps from the incoming audio */ if (GST_BUFFER_TIMESTAMP (inbuf) != GST_CLOCK_TIME_NONE) monoscope->next_ts = GST_BUFFER_TIMESTAMP (inbuf); GST_LOG_OBJECT (monoscope, "in buffer has %d samples, ts=%" GST_TIME_FORMAT, gst_buffer_get_size (inbuf) / monoscope->bps, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf))); gst_adapter_push (monoscope->adapter, inbuf); inbuf = NULL; /* Collect samples until we have enough for an output frame */ while (flow_ret == GST_FLOW_OK) { gint16 *samples; GstBuffer *outbuf = NULL; guint32 *pixels, avail, bytesperframe; avail = gst_adapter_available (monoscope->adapter); GST_LOG_OBJECT (monoscope, "bytes avail now %u", avail); bytesperframe = monoscope->spf * monoscope->bps; if (avail < bytesperframe) break; /* FIXME: something is wrong with QoS, we are skipping way too much * stuff even with very low CPU loads */ #if 0 if (monoscope->next_ts != -1) { gboolean need_skip; gint64 qostime; qostime = gst_segment_to_running_time (&monoscope->segment, GST_FORMAT_TIME, monoscope->next_ts); GST_OBJECT_LOCK (monoscope); /* check for QoS, don't compute buffers that are known to be late */ need_skip = GST_CLOCK_TIME_IS_VALID (monoscope->earliest_time) && qostime <= monoscope->earliest_time; GST_OBJECT_UNLOCK (monoscope); if (need_skip) { GST_WARNING_OBJECT (monoscope, "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (monoscope->earliest_time)); goto skip; } } #endif samples = (gint16 *) gst_adapter_map (monoscope->adapter, bytesperframe); if (monoscope->spf < 512) { gint16 in_data[512], i; for (i = 0; i < 512; ++i) { gdouble off; off = ((gdouble) i * (gdouble) monoscope->spf) / 512.0; in_data[i] = samples[MIN ((guint) off, monoscope->spf)]; } pixels = monoscope_update (monoscope->visstate, in_data); } else { /* not really correct, but looks much prettier */ pixels = monoscope_update (monoscope->visstate, samples); } GST_LOG_OBJECT (monoscope, "allocating output buffer"); flow_ret = gst_buffer_pool_acquire_buffer (monoscope->pool, &outbuf, NULL); if (flow_ret != GST_FLOW_OK) { gst_adapter_unmap (monoscope->adapter); goto out; } gst_buffer_fill (outbuf, 0, pixels, monoscope->outsize); GST_BUFFER_TIMESTAMP (outbuf) = monoscope->next_ts; GST_BUFFER_DURATION (outbuf) = monoscope->frame_duration; flow_ret = gst_pad_push (monoscope->srcpad, outbuf); #if 0 skip: #endif if (GST_CLOCK_TIME_IS_VALID (monoscope->next_ts)) monoscope->next_ts += monoscope->frame_duration; gst_adapter_flush (monoscope->adapter, bytesperframe); } out: return flow_ret; }
static GstFlowReturn gst_visual_chain (GstPad * pad, GstBuffer * buffer) { GstBuffer *outbuf = NULL; guint i; GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad)); GstFlowReturn ret = GST_FLOW_OK; guint avail; GST_DEBUG_OBJECT (visual, "chain function called"); /* If we don't have an output format yet, preallocate a buffer to try and * set one */ if (GST_PAD_CAPS (visual->srcpad) == NULL) { ret = get_buffer (visual, &outbuf); if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); goto beach; } } /* resync on DISCONT */ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (visual->adapter); } GST_DEBUG_OBJECT (visual, "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer) / visual->bps, GST_BUFFER_TIMESTAMP (buffer)); gst_adapter_push (visual->adapter, buffer); while (TRUE) { gboolean need_skip; const guint16 *data; guint64 dist, timestamp; GST_DEBUG_OBJECT (visual, "processing buffer"); avail = gst_adapter_available (visual->adapter); GST_DEBUG_OBJECT (visual, "avail now %u", avail); /* we need at least 512 samples */ if (avail < 512 * visual->bps) break; /* we need at least enough samples to make one frame */ if (avail < visual->spf * visual->bps) break; /* get timestamp of the current adapter byte */ timestamp = gst_adapter_prev_timestamp (visual->adapter, &dist); if (GST_CLOCK_TIME_IS_VALID (timestamp)) { /* convert bytes to time */ dist /= visual->bps; timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, visual->rate); } if (timestamp != -1) { gint64 qostime; /* QoS is done on running time */ qostime = gst_segment_to_running_time (&visual->segment, GST_FORMAT_TIME, timestamp); GST_OBJECT_LOCK (visual); /* check for QoS, don't compute buffers that are known to be late */ need_skip = visual->earliest_time != -1 && qostime <= visual->earliest_time; GST_OBJECT_UNLOCK (visual); if (need_skip) { GST_WARNING_OBJECT (visual, "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (visual->earliest_time)); goto skip; } } /* Read 512 samples per channel */ data = (const guint16 *) gst_adapter_peek (visual->adapter, 512 * visual->bps); #if defined(VISUAL_API_VERSION) && VISUAL_API_VERSION >= 4000 && VISUAL_API_VERSION < 5000 { VisBuffer *lbuf, *rbuf; guint16 ldata[512], rdata[512]; VisAudioSampleRateType rate; lbuf = visual_buffer_new_with_buffer (ldata, sizeof (ldata), NULL); rbuf = visual_buffer_new_with_buffer (rdata, sizeof (rdata), NULL); if (visual->channels == 2) { for (i = 0; i < 512; i++) { ldata[i] = *data++; rdata[i] = *data++; } } else { for (i = 0; i < 512; i++) { ldata[i] = *data; rdata[i] = *data++; } } switch (visual->rate) { case 8000: rate = VISUAL_AUDIO_SAMPLE_RATE_8000; break; case 11250: rate = VISUAL_AUDIO_SAMPLE_RATE_11250; break; case 22500: rate = VISUAL_AUDIO_SAMPLE_RATE_22500; break; case 32000: rate = VISUAL_AUDIO_SAMPLE_RATE_32000; break; case 44100: rate = VISUAL_AUDIO_SAMPLE_RATE_44100; break; case 48000: rate = VISUAL_AUDIO_SAMPLE_RATE_48000; break; case 96000: rate = VISUAL_AUDIO_SAMPLE_RATE_96000; break; default: visual_object_unref (VISUAL_OBJECT (lbuf)); visual_object_unref (VISUAL_OBJECT (rbuf)); GST_ERROR_OBJECT (visual, "unsupported rate %d", visual->rate); ret = GST_FLOW_ERROR; goto beach; break; } visual_audio_samplepool_input_channel (visual->audio->samplepool, lbuf, rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, (char *) VISUAL_AUDIO_CHANNEL_LEFT); visual_audio_samplepool_input_channel (visual->audio->samplepool, rbuf, rate, VISUAL_AUDIO_SAMPLE_FORMAT_S16, (char *) VISUAL_AUDIO_CHANNEL_RIGHT); visual_object_unref (VISUAL_OBJECT (lbuf)); visual_object_unref (VISUAL_OBJECT (rbuf)); } #else if (visual->channels == 2) { for (i = 0; i < 512; i++) { visual->audio->plugpcm[0][i] = *data++; visual->audio->plugpcm[1][i] = *data++; } } else { for (i = 0; i < 512; i++) { visual->audio->plugpcm[0][i] = *data; visual->audio->plugpcm[1][i] = *data++; } } #endif /* alloc a buffer if we don't have one yet, this happens * when we pushed a buffer in this while loop before */ if (outbuf == NULL) { ret = get_buffer (visual, &outbuf); if (ret != GST_FLOW_OK) { goto beach; } } visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf)); visual_audio_analyze (visual->audio); visual_actor_run (visual->actor, visual->audio); visual_video_set_buffer (visual->video, NULL); GST_DEBUG_OBJECT (visual, "rendered one frame"); GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = visual->duration; ret = gst_pad_push (visual->srcpad, outbuf); outbuf = NULL; skip: GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input", visual->spf); /* Flush out the number of samples per frame */ gst_adapter_flush (visual->adapter, visual->spf * visual->bps); /* quit the loop if something was wrong */ if (ret != GST_FLOW_OK) break; } beach: if (outbuf != NULL) gst_buffer_unref (outbuf); gst_object_unref (visual); return ret; }
static GstFlowReturn gst_y4m_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstY4mDec *y4mdec; int n_avail; GstFlowReturn flow_ret = GST_FLOW_OK; #define MAX_HEADER_LENGTH 80 char header[MAX_HEADER_LENGTH]; int i; int len; y4mdec = GST_Y4M_DEC (parent); GST_DEBUG_OBJECT (y4mdec, "chain"); if (GST_BUFFER_IS_DISCONT (buffer)) { GST_DEBUG ("got discont"); gst_adapter_clear (y4mdec->adapter); } gst_adapter_push (y4mdec->adapter, buffer); n_avail = gst_adapter_available (y4mdec->adapter); if (!y4mdec->have_header) { gboolean ret; GstCaps *caps; if (n_avail < MAX_HEADER_LENGTH) return GST_FLOW_OK; gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); header[MAX_HEADER_LENGTH - 1] = 0; for (i = 0; i < MAX_HEADER_LENGTH; i++) { if (header[i] == 0x0a) header[i] = 0; } ret = gst_y4m_dec_parse_header (y4mdec, header); if (!ret) { GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, ("Failed to parse YUV4MPEG header"), (NULL)); return GST_FLOW_ERROR; } y4mdec->header_size = strlen (header) + 1; gst_adapter_flush (y4mdec->adapter, y4mdec->header_size); caps = gst_video_info_to_caps (&y4mdec->info); ret = gst_pad_set_caps (y4mdec->srcpad, caps); gst_caps_unref (caps); if (!ret) { GST_DEBUG_OBJECT (y4mdec, "Couldn't set caps on src pad"); return GST_FLOW_ERROR; } y4mdec->have_header = TRUE; } if (y4mdec->have_new_segment) { GstEvent *event; GstClockTime start = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment.start); GstClockTime stop = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment.stop); GstClockTime time = gst_y4m_dec_bytes_to_timestamp (y4mdec, y4mdec->segment.time); GstSegment seg; gst_segment_init (&seg, GST_FORMAT_TIME); seg.start = start; seg.stop = stop; seg.time = time; event = gst_event_new_segment (&seg); gst_pad_push_event (y4mdec->srcpad, event); //gst_event_unref (event); y4mdec->have_new_segment = FALSE; y4mdec->frame_index = gst_y4m_dec_bytes_to_frames (y4mdec, y4mdec->segment.time); GST_DEBUG ("new frame_index %d", y4mdec->frame_index); } while (1) { n_avail = gst_adapter_available (y4mdec->adapter); if (n_avail < MAX_HEADER_LENGTH) break; gst_adapter_copy (y4mdec->adapter, (guint8 *) header, 0, MAX_HEADER_LENGTH); header[MAX_HEADER_LENGTH - 1] = 0; for (i = 0; i < MAX_HEADER_LENGTH; i++) { if (header[i] == 0x0a) header[i] = 0; } if (memcmp (header, "FRAME", 5) != 0) { GST_ELEMENT_ERROR (y4mdec, STREAM, DECODE, ("Failed to parse YUV4MPEG frame"), (NULL)); flow_ret = GST_FLOW_ERROR; break; } len = strlen (header); if (n_avail < y4mdec->info.size + len + 1) { /* not enough data */ GST_DEBUG ("not enough data for frame %d < %" G_GSIZE_FORMAT, n_avail, y4mdec->info.size + len + 1); break; } gst_adapter_flush (y4mdec->adapter, len + 1); buffer = gst_adapter_take_buffer (y4mdec->adapter, y4mdec->info.size); GST_BUFFER_TIMESTAMP (buffer) = gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index); GST_BUFFER_DURATION (buffer) = gst_y4m_dec_frames_to_timestamp (y4mdec, y4mdec->frame_index + 1) - GST_BUFFER_TIMESTAMP (buffer); y4mdec->frame_index++; flow_ret = gst_pad_push (y4mdec->srcpad, buffer); if (flow_ret != GST_FLOW_OK) break; } GST_DEBUG ("returning %d", flow_ret); return flow_ret; }
static GstBuffer * gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstBuffer * buf) { GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay); GstBuffer *payload; guint8 *data; guint hdrsize; guint size; GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT; if (G_UNLIKELY (GST_BUFFER_IS_DISCONT (buf))) { GST_LOG_OBJECT (self, "Discontinuity, flushing adapter"); gst_adapter_clear (self->adapter); self->started = FALSE; } gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuffer); size = gst_rtp_buffer_get_payload_len (&rtpbuffer); /* At least one header and one vp8 byte */ if (G_UNLIKELY (size < 2)) goto too_small; data = gst_rtp_buffer_get_payload (&rtpbuffer); if (G_UNLIKELY (!self->started)) { /* Check if this is the start of a VP8 frame, otherwise bail */ /* S=1 and PartID= 0 */ if ((data[0] & 0x1F) != 0x10) goto done; self->started = TRUE; } hdrsize = 1; /* Check X optional header */ if ((data[0] & 0x80) != 0) { hdrsize++; /* Check I optional header */ if ((data[1] & 0x80) != 0) { if (G_UNLIKELY (size < 3)) goto too_small; hdrsize++; /* Check for 16 bits PictureID */ if ((data[2] & 0x80) != 0) hdrsize++; } /* Check L optional header */ if ((data[1] & 0x40) != 0) hdrsize++; /* Check T or K optional headers */ if ((data[1] & 0x20) != 0 || (data[1] & 0x10) != 0) hdrsize++; } 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 (&rtpbuffer, hdrsize, -1); gst_adapter_push (self->adapter, payload); /* Marker indicates that it was the last rtp packet for this frame */ if (gst_rtp_buffer_get_marker (&rtpbuffer)) { GstBuffer *out; guint8 flag0; gst_adapter_copy (self->adapter, &flag0, 0, 1); out = gst_adapter_take_buffer (self->adapter, gst_adapter_available (self->adapter)); self->started = FALSE; gst_rtp_buffer_unmap (&rtpbuffer); /* mark keyframes */ out = gst_buffer_make_writable (out); if ((flag0 & 0x01)) GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DELTA_UNIT); else GST_BUFFER_FLAG_UNSET (out, GST_BUFFER_FLAG_DELTA_UNIT); return out; } done: gst_rtp_buffer_unmap (&rtpbuffer); 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 gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer) { GstH264Parse *h264parse = GST_H264_PARSE (GST_PAD_PARENT (pad)); if (h264parse->packetized && buffer) { GstByteReader br; GstBuffer *sub; GstFlowReturn ret = GST_FLOW_OK; guint32 len; const guint nl = h264parse->nal_length_size; GST_LOG_OBJECT (h264parse, "processing packet buffer of size %d", GST_BUFFER_SIZE (buffer)); gst_byte_reader_init_from_buffer (&br, buffer); while (ret == GST_FLOW_OK && gst_byte_reader_get_remaining (&br)) { GST_DEBUG_OBJECT (h264parse, "AVC nal offset %d", gst_byte_reader_get_pos (&br)); if (gst_byte_reader_get_remaining (&br) < nl) goto parse_failed; switch (nl) { case 4: len = gst_byte_reader_get_uint32_be_unchecked (&br); break; case 3: len = gst_byte_reader_get_uint24_be_unchecked (&br); break; case 2: len = gst_byte_reader_get_uint16_be_unchecked (&br); break; case 1: len = gst_byte_reader_get_uint8_unchecked (&br); break; default: goto not_negotiated; break; } GST_DEBUG_OBJECT (h264parse, "AVC nal size %d", len); if (gst_byte_reader_get_remaining (&br) < len) goto parse_failed; if (h264parse->split_packetized) { /* convert to NAL aligned byte stream input */ sub = gst_h264_parse_wrap_nal (h264parse, GST_H264_PARSE_FORMAT_BYTE, (guint8 *) gst_byte_reader_get_data_unchecked (&br, len), len); /* at least this should make sense */ GST_BUFFER_TIMESTAMP (sub) = GST_BUFFER_TIMESTAMP (buffer); GST_LOG_OBJECT (h264parse, "pushing NAL of size %d", len); ret = h264parse->parse_chain (pad, sub); } else { /* pass-through: no looking for frames (and nal processing), * so need to parse to collect data here */ /* NOTE: so if it is really configured to do so, * pre_push can/will still insert codec-data at intervals, * which is not really pure pass-through, but anyway ... */ gst_h264_parse_process_nal (h264parse, GST_BUFFER_DATA (buffer), gst_byte_reader_get_pos (&br) - nl, gst_byte_reader_get_pos (&br), len); gst_byte_reader_skip_unchecked (&br, len); } } if (h264parse->split_packetized) return ret; } exit: /* nal processing in pass-through might have collected stuff; * ensure nothing happens with this later on */ gst_adapter_clear (h264parse->frame_out); return h264parse->parse_chain (pad, buffer); /* ERRORS */ not_negotiated: { GST_DEBUG_OBJECT (h264parse, "insufficient data to split input"); return GST_FLOW_NOT_NEGOTIATED; } parse_failed: { if (h264parse->split_packetized) { GST_ELEMENT_ERROR (h264parse, STREAM, FAILED, (NULL), ("invalid AVC input data")); return GST_FLOW_ERROR; } else { /* do not meddle to much in this case */ GST_DEBUG_OBJECT (h264parse, "parsing packet failed"); goto exit; } } }
static GstFlowReturn gst_goom_chain (GstPad * pad, GstBuffer * buffer) { GstGoom *goom; GstFlowReturn ret; GstBuffer *outbuf = NULL; goom = GST_GOOM (gst_pad_get_parent (pad)); if (goom->bps == 0) { ret = GST_FLOW_NOT_NEGOTIATED; goto beach; } /* If we don't have an output format yet, preallocate a buffer to try and * set one */ if (GST_PAD_CAPS (goom->srcpad) == NULL) { ret = get_buffer (goom, &outbuf); if (ret != GST_FLOW_OK) { gst_buffer_unref (buffer); goto beach; } } /* don't try to combine samples from discont buffer */ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (goom->adapter); } GST_DEBUG_OBJECT (goom, "Input buffer has %d samples, time=%" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buffer) / goom->bps, GST_BUFFER_TIMESTAMP (buffer)); /* Collect samples until we have enough for an output frame */ gst_adapter_push (goom->adapter, buffer); ret = GST_FLOW_OK; while (TRUE) { const guint16 *data; gboolean need_skip; guchar *out_frame; gint i; guint avail, to_flush; guint64 dist, timestamp; avail = gst_adapter_available (goom->adapter); GST_DEBUG_OBJECT (goom, "avail now %u", avail); /* we need GOOM_SAMPLES to get a meaningful result from goom. */ if (avail < (GOOM_SAMPLES * goom->bps)) break; /* we also need enough samples to produce one frame at least */ if (avail < goom->bpf) break; GST_DEBUG_OBJECT (goom, "processing buffer"); /* get timestamp of the current adapter byte */ timestamp = gst_adapter_prev_timestamp (goom->adapter, &dist); if (GST_CLOCK_TIME_IS_VALID (timestamp)) { /* convert bytes to time */ dist /= goom->bps; timestamp += gst_util_uint64_scale_int (dist, GST_SECOND, goom->rate); } if (timestamp != -1) { gint64 qostime; qostime = gst_segment_to_running_time (&goom->segment, GST_FORMAT_TIME, timestamp); qostime += goom->duration; GST_OBJECT_LOCK (goom); /* check for QoS, don't compute buffers that are known to be late */ need_skip = goom->earliest_time != -1 && qostime <= goom->earliest_time; GST_OBJECT_UNLOCK (goom); if (need_skip) { GST_WARNING_OBJECT (goom, "QoS: skip ts: %" GST_TIME_FORMAT ", earliest: %" GST_TIME_FORMAT, GST_TIME_ARGS (qostime), GST_TIME_ARGS (goom->earliest_time)); goto skip; } } /* get next GOOM_SAMPLES, we have at least this amount of samples */ data = (const guint16 *) gst_adapter_peek (goom->adapter, GOOM_SAMPLES * goom->bps); if (goom->channels == 2) { for (i = 0; i < GOOM_SAMPLES; i++) { goom->datain[0][i] = *data++; goom->datain[1][i] = *data++; } } else { for (i = 0; i < GOOM_SAMPLES; i++) { goom->datain[0][i] = *data; goom->datain[1][i] = *data++; } } /* alloc a buffer if we don't have one yet, this happens * when we pushed a buffer in this while loop before */ if (outbuf == NULL) { ret = get_buffer (goom, &outbuf); if (ret != GST_FLOW_OK) { goto beach; } } GST_BUFFER_TIMESTAMP (outbuf) = timestamp; GST_BUFFER_DURATION (outbuf) = goom->duration; GST_BUFFER_SIZE (outbuf) = goom->outsize; out_frame = (guchar *) goom_update (goom->plugin, goom->datain, 0, 0); memcpy (GST_BUFFER_DATA (outbuf), out_frame, goom->outsize); GST_DEBUG ("Pushing frame with time=%" GST_TIME_FORMAT ", duration=%" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (goom->duration)); ret = gst_pad_push (goom->srcpad, outbuf); outbuf = NULL; skip: /* Now flush the samples we needed for this frame, which might be more than * the samples we used (GOOM_SAMPLES). */ to_flush = goom->bpf; GST_DEBUG_OBJECT (goom, "finished frame, flushing %u bytes from input", to_flush); gst_adapter_flush (goom->adapter, to_flush); if (ret != GST_FLOW_OK) break; } if (outbuf != NULL) gst_buffer_unref (outbuf); beach: gst_object_unref (goom); return ret; }
static GstBuffer * gst_rtp_sv3v_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf) { GstRtpSV3VDepay *rtpsv3vdepay; GstBuffer *outbuf; guint16 seq; rtpsv3vdepay = GST_RTP_SV3V_DEPAY (depayload); if (!gst_rtp_buffer_validate (buf)) goto bad_packet; /* flush on sequence number gaps */ seq = gst_rtp_buffer_get_seq (buf); if (seq != rtpsv3vdepay->nextseq) { gst_adapter_clear (rtpsv3vdepay->adapter); } rtpsv3vdepay->nextseq = seq + 1; { gint payload_len; guint8 *payload; gboolean M; gboolean C, S, E; payload_len = gst_rtp_buffer_get_payload_len (buf); if (payload_len < 3) goto bad_packet; payload = gst_rtp_buffer_get_payload (buf); M = gst_rtp_buffer_get_marker (buf); /* This is all a guess: * 1 1 1 1 1 1 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |0|C|S|E|0|0|0|0|0|0|0|0|0|0|0|0| * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * C: config, packet contains config info * S: start, packet contains start of frame * E: end, packet contains end of frame */ /* this seems to indicate a packet with a config string sent before each * keyframe */ C = (payload[0] & 0x40) == 0x40; /* redundant with the RTP marker bit */ S = (payload[0] & 0x20) == 0x20; E = (payload[0] & 0x10) == 0x10; if (C) { GstCaps *caps; GstBuffer *codec_data; GValue value = { 0 }; /* if we already have caps, we don't need to do anything. FIXME, check if * something changed. */ if (GST_PAD_CAPS (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload))) return NULL; /* No idea... These are the two examples I found.. */ if (payload[2] == 0x1d) { rtpsv3vdepay->width = 160; rtpsv3vdepay->height = 128; } else if (payload[2] == 0xdd) { rtpsv3vdepay->width = 320; rtpsv3vdepay->height = 240; } /* we need a dummy empty codec data */ g_value_init (&value, GST_TYPE_BUFFER); gst_value_deserialize (&value, ""); codec_data = gst_value_get_buffer (&value); caps = gst_caps_new_simple ("video/x-svq", "svqversion", G_TYPE_INT, 3, "width", G_TYPE_INT, rtpsv3vdepay->width, "height", G_TYPE_INT, rtpsv3vdepay->height, "codec_data", GST_TYPE_BUFFER, codec_data, NULL); gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps); gst_caps_unref (caps); g_value_unset (&value); return NULL; } /* store data in adapter, stip off 2 bytes header */ outbuf = gst_rtp_buffer_get_payload_subbuffer (buf, 2, -1); gst_adapter_push (rtpsv3vdepay->adapter, outbuf); if (M) { /* frame is completed: push contents of adapter */ guint avail; avail = gst_adapter_available (rtpsv3vdepay->adapter); outbuf = gst_adapter_take_buffer (rtpsv3vdepay->adapter, avail); /* timestamp for complete buffer is that of last buffer as well */ gst_buffer_set_caps (outbuf, GST_PAD_CAPS (depayload->srcpad)); return outbuf; } } return NULL; /* ERRORS */ bad_packet: { GST_ELEMENT_WARNING (rtpsv3vdepay, STREAM, DECODE, ("Packet did not validate"), (NULL)); return NULL; } }
static GstFlowReturn gst_voamrwbenc_chain (GstPad * pad, GstBuffer * buffer) { GstVoAmrWbEnc *amrwbenc; GstFlowReturn ret = GST_FLOW_OK; const int buffer_size = sizeof (short) * L_FRAME16k; amrwbenc = GST_VOAMRWBENC (gst_pad_get_parent (pad)); g_return_val_if_fail (amrwbenc->handle, GST_FLOW_WRONG_STATE); if (amrwbenc->rate == 0 || amrwbenc->channels == 0) { ret = GST_FLOW_NOT_NEGOTIATED; goto done; } /* discontinuity clears adapter, FIXME, maybe we can set some * encoder flag to mask the discont. */ if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) { gst_adapter_clear (amrwbenc->adapter); amrwbenc->ts = 0; amrwbenc->discont = TRUE; } if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) amrwbenc->ts = GST_BUFFER_TIMESTAMP (buffer); ret = GST_FLOW_OK; gst_adapter_push (amrwbenc->adapter, buffer); /* Collect samples until we have enough for an output frame */ while (gst_adapter_available (amrwbenc->adapter) >= buffer_size) { GstBuffer *out; guint8 *data; gint outsize; out = gst_buffer_new_and_alloc (buffer_size); GST_BUFFER_DURATION (out) = GST_SECOND * L_FRAME16k / (amrwbenc->rate * amrwbenc->channels); GST_BUFFER_TIMESTAMP (out) = amrwbenc->ts; if (amrwbenc->ts != -1) { amrwbenc->ts += GST_BUFFER_DURATION (out); } if (amrwbenc->discont) { GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT); amrwbenc->discont = FALSE; } gst_buffer_set_caps (out, gst_pad_get_caps (amrwbenc->srcpad)); data = (guint8 *) gst_adapter_peek (amrwbenc->adapter, buffer_size); /* encode */ outsize = E_IF_encode (amrwbenc->handle, amrwbenc->bandmode, (const short *) data, (unsigned char *) GST_BUFFER_DATA (out), 0); gst_adapter_flush (amrwbenc->adapter, buffer_size); GST_BUFFER_SIZE (out) = outsize; /* play */ if ((ret = gst_pad_push (amrwbenc->srcpad, out)) != GST_FLOW_OK) break; } done: gst_object_unref (amrwbenc); return ret; }