static GstFlowReturn gst_asf_parse_pull_headers (GstAsfParse * asfparse) { GstBuffer *guid_and_size = NULL; GstBuffer *headers = NULL; guint64 size; GstFlowReturn ret; GstMapInfo map; if ((ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset, ASF_GUID_OBJSIZE_SIZE, &guid_and_size)) != GST_FLOW_OK) { GST_ERROR_OBJECT (asfparse, "Failed to pull data from headers"); goto leave; } asfparse->offset += ASF_GUID_OBJSIZE_SIZE; gst_buffer_map (guid_and_size, &map, GST_MAP_READ); size = gst_asf_match_and_peek_obj_size (map.data, &(guids[ASF_HEADER_OBJECT_INDEX])); gst_buffer_unmap (guid_and_size, &map); if (size == 0) { GST_ERROR_OBJECT (asfparse, "ASF starting identifier missing"); goto leave; } if ((ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset, size - ASF_GUID_OBJSIZE_SIZE, &headers)) != GST_FLOW_OK) { GST_ERROR_OBJECT (asfparse, "Failed to pull data from headers"); goto leave; } headers = gst_buffer_append (guid_and_size, headers); guid_and_size = NULL; asfparse->offset += size - ASF_GUID_OBJSIZE_SIZE; if (!gst_asf_parse_headers (headers, asfparse->asfinfo)) { goto leave; } return gst_asf_parse_push (asfparse, headers); leave: if (headers) gst_buffer_unref (headers); if (guid_and_size) gst_buffer_unref (guid_and_size); return ret; }
static GstFlowReturn gst_asf_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) { GstAsfParse *asfparse; GstFlowReturn ret = GST_FLOW_OK; asfparse = GST_ASF_PARSE (parent); gst_adapter_push (asfparse->adapter, buffer); switch (asfparse->parse_state) { case ASF_PARSING_HEADERS: if (asfparse->headers_size == 0 && gst_adapter_available (asfparse->adapter) >= ASF_GUID_OBJSIZE_SIZE) { /* we can peek at the object size */ asfparse->headers_size = gst_asf_match_and_peek_obj_size (gst_adapter_map (asfparse->adapter, ASF_GUID_OBJSIZE_SIZE), &(guids[ASF_HEADER_OBJECT_INDEX])); gst_adapter_unmap (asfparse->adapter); if (asfparse->headers_size == 0) { /* something is wrong, this probably ain't an ASF stream */ GST_ERROR_OBJECT (asfparse, "ASF starting identifier missing"); ret = GST_FLOW_ERROR; goto end; } } if (gst_adapter_available (asfparse->adapter) >= asfparse->headers_size) { GstBuffer *headers = gst_adapter_take_buffer (asfparse->adapter, asfparse->headers_size); if (gst_asf_parse_headers (headers, asfparse->asfinfo)) { ret = gst_asf_parse_push (asfparse, headers); asfparse->parse_state = ASF_PARSING_DATA; } else { ret = GST_FLOW_ERROR; GST_ERROR_OBJECT (asfparse, "Failed to parse headers"); } } break; case ASF_PARSING_DATA: if (asfparse->data_size == 0 && gst_adapter_available (asfparse->adapter) >= ASF_GUID_OBJSIZE_SIZE) { /* we can peek at the object size */ asfparse->data_size = gst_asf_match_and_peek_obj_size (gst_adapter_map (asfparse->adapter, ASF_GUID_OBJSIZE_SIZE), &(guids[ASF_DATA_OBJECT_INDEX])); gst_adapter_unmap (asfparse->adapter); if (asfparse->data_size == 0) { /* something is wrong */ GST_ERROR_OBJECT (asfparse, "Unexpected object after headers, was " "expecting a data object"); ret = GST_FLOW_ERROR; goto end; } } /* if we have received the full data object headers */ if (gst_adapter_available (asfparse->adapter) >= ASF_DATA_OBJECT_SIZE) { ret = gst_asf_parse_parse_data_object (asfparse, gst_adapter_take_buffer (asfparse->adapter, ASF_DATA_OBJECT_SIZE)); if (ret != GST_FLOW_OK) { goto end; } asfparse->parse_state = ASF_PARSING_PACKETS; } break; case ASF_PARSING_PACKETS: g_assert (asfparse->asfinfo->packet_size); while ((asfparse->asfinfo->broadcast || asfparse->parsed_packets < asfparse->asfinfo->packets_count) && gst_adapter_available (asfparse->adapter) >= asfparse->asfinfo->packet_size) { GstBuffer *packet = gst_adapter_take_buffer (asfparse->adapter, asfparse->asfinfo->packet_size); asfparse->parsed_packets++; ret = gst_asf_parse_parse_packet (asfparse, packet); if (ret != GST_FLOW_OK) goto end; } if (!asfparse->asfinfo->broadcast && asfparse->parsed_packets >= asfparse->asfinfo->packets_count) { GST_INFO_OBJECT (asfparse, "Finished parsing packets"); asfparse->parse_state = ASF_PARSING_INDEXES; } break; case ASF_PARSING_INDEXES: /* we currently don't care about any of those objects */ if (gst_adapter_available (asfparse->adapter) >= ASF_GUID_OBJSIZE_SIZE) { guint64 obj_size; /* we can peek at the object size */ obj_size = gst_asf_match_and_peek_obj_size (gst_adapter_map (asfparse->adapter, ASF_GUID_OBJSIZE_SIZE), NULL); gst_adapter_unmap (asfparse->adapter); if (gst_adapter_available (asfparse->adapter) >= obj_size) { GST_DEBUG_OBJECT (asfparse, "Skiping object"); ret = gst_asf_parse_push (asfparse, gst_adapter_take_buffer (asfparse->adapter, obj_size)); if (ret != GST_FLOW_OK) { goto end; } } } break; default: break; } end: return ret; }
static GstFlowReturn gst_rtp_asf_pay_handle_buffer (GstBaseRTPPayload * rtppay, GstBuffer * buffer) { GstRtpAsfPay *rtpasfpay = GST_RTP_ASF_PAY_CAST (rtppay); if (G_UNLIKELY (rtpasfpay->state == ASF_END)) { GST_LOG_OBJECT (rtpasfpay, "Dropping buffer as we already pushed all packets"); gst_buffer_unref (buffer); return GST_FLOW_UNEXPECTED; /* we already finished our job */ } /* receive headers * we only accept if they are in a single buffer */ if (G_UNLIKELY (rtpasfpay->state == ASF_NOT_STARTED)) { guint64 header_size; if (GST_BUFFER_SIZE (buffer) < 24) { /* guid+object size size */ GST_ERROR_OBJECT (rtpasfpay, "Buffer too small, smaller than a Guid and object size"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } header_size = gst_asf_match_and_peek_obj_size (GST_BUFFER_DATA (buffer), &(guids[ASF_HEADER_OBJECT_INDEX])); if (header_size > 0) { GST_DEBUG_OBJECT (rtpasfpay, "ASF header guid received, size %" G_GUINT64_FORMAT, header_size); if (GST_BUFFER_SIZE (buffer) < header_size) { GST_ERROR_OBJECT (rtpasfpay, "Headers should be contained in a single" " buffer"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } else { rtpasfpay->state = ASF_DATA_OBJECT; /* clear previous headers, if any */ if (rtpasfpay->headers) { gst_buffer_unref (rtpasfpay->headers); } GST_DEBUG_OBJECT (rtpasfpay, "Storing headers"); if (GST_BUFFER_SIZE (buffer) == header_size) { rtpasfpay->headers = buffer; return GST_FLOW_OK; } else { /* headers are a subbuffer of thie buffer */ GstBuffer *aux = gst_buffer_create_sub (buffer, header_size, GST_BUFFER_SIZE (buffer) - header_size); rtpasfpay->headers = gst_buffer_create_sub (buffer, 0, header_size); gst_buffer_replace (&buffer, aux); } } } else { GST_ERROR_OBJECT (rtpasfpay, "Missing ASF header start"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } } if (G_UNLIKELY (rtpasfpay->state == ASF_DATA_OBJECT)) { if (GST_BUFFER_SIZE (buffer) != ASF_DATA_OBJECT_SIZE) { GST_ERROR_OBJECT (rtpasfpay, "Received buffer of different size of " "the data object header"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } if (gst_asf_match_guid (GST_BUFFER_DATA (buffer), &(guids[ASF_DATA_OBJECT_INDEX]))) { GST_DEBUG_OBJECT (rtpasfpay, "Received data object header"); rtpasfpay->headers = gst_buffer_join (rtpasfpay->headers, buffer); rtpasfpay->state = ASF_PACKETS; return gst_rtp_asf_pay_parse_headers (rtpasfpay); } else { GST_ERROR_OBJECT (rtpasfpay, "Unexpected object received (was expecting " "data object)"); gst_buffer_unref (buffer); return GST_FLOW_ERROR; } } if (G_LIKELY (rtpasfpay->state == ASF_PACKETS)) { /* in broadcast mode we can't trust the packets count information * from the headers * We assume that if this is on broadcast mode it is a live stream * and we are going to keep receiving packets indefinitely */ if (rtpasfpay->asfinfo.broadcast || rtpasfpay->packets_count < rtpasfpay->asfinfo.packets_count) { GST_DEBUG_OBJECT (rtpasfpay, "Received packet %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, rtpasfpay->packets_count, rtpasfpay->asfinfo.packets_count); rtpasfpay->packets_count++; return gst_rtp_asf_pay_handle_packet (rtpasfpay, buffer); } else { GST_INFO_OBJECT (rtpasfpay, "Packets ended"); rtpasfpay->state = ASF_END; gst_buffer_unref (buffer); return GST_FLOW_UNEXPECTED; } } gst_buffer_unref (buffer); return GST_FLOW_OK; }