mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 19:51:11 +00:00
asfparse: port to baseparse
asfparse was not really functional after the port to 1.0 Now porting it to baseparse to get it working again
This commit is contained in:
parent
6cf1f629a3
commit
04134671c9
4 changed files with 272 additions and 473 deletions
|
@ -761,26 +761,36 @@ gst_asf_parse_file_properties_obj (GstByteReader * reader,
|
|||
|
||||
gboolean
|
||||
gst_asf_parse_headers (GstBuffer * buffer, GstAsfFileInfo * file_info)
|
||||
{
|
||||
GstMapInfo map;
|
||||
gboolean ret;
|
||||
|
||||
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
||||
ret = gst_asf_parse_headers_from_data (map.data, map.size, file_info);
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_asf_parse_headers_from_data (guint8 * data, guint size,
|
||||
GstAsfFileInfo * file_info)
|
||||
{
|
||||
gboolean ret = TRUE;
|
||||
guint32 header_objects = 0;
|
||||
guint32 i;
|
||||
GstByteReader *reader;
|
||||
guint64 object_size;
|
||||
GstMapInfo map;
|
||||
|
||||
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
||||
|
||||
object_size = gst_asf_match_and_peek_obj_size (map.data,
|
||||
object_size = gst_asf_match_and_peek_obj_size (data,
|
||||
&(guids[ASF_HEADER_OBJECT_INDEX]));
|
||||
if (object_size == 0) {
|
||||
GST_WARNING ("ASF: Cannot parse, header guid not found at the beginning "
|
||||
" of data");
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
reader = gst_byte_reader_new (map.data, map.size);
|
||||
reader = gst_byte_reader_new (data, size);
|
||||
|
||||
if (!gst_byte_reader_skip (reader, ASF_GUID_OBJSIZE_SIZE))
|
||||
goto error;
|
||||
|
@ -818,7 +828,6 @@ error:
|
|||
ret = FALSE;
|
||||
GST_WARNING ("ASF: Error while parsing headers");
|
||||
end:
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
gst_byte_reader_free (reader);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ guint64 gst_asf_match_and_peek_obj_size (const guint8 * data,
|
|||
guint64 gst_asf_match_and_peek_obj_size_buf (GstBuffer * buf,
|
||||
const Guid * guid);
|
||||
gboolean gst_asf_parse_headers (GstBuffer * buffer, GstAsfFileInfo * file_info);
|
||||
gboolean gst_asf_parse_headers_from_data (guint8 * data, guint size, GstAsfFileInfo * file_info);
|
||||
|
||||
/* ASF tags
|
||||
* found at http://msdn.microsoft.com/en-us/library/dd562330(VS.85).aspx
|
||||
|
|
|
@ -42,99 +42,46 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
|
|||
GST_STATIC_CAPS ("video/x-ms-asf, parsed = (boolean) false")
|
||||
);
|
||||
|
||||
static GstStateChangeReturn gst_asf_parse_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
static void gst_asf_parse_loop (GstPad * pad);
|
||||
|
||||
#define gst_asf_parse_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstAsfParse, gst_asf_parse, GST_TYPE_ELEMENT);
|
||||
G_DEFINE_TYPE (GstAsfParse, gst_asf_parse, GST_TYPE_BASE_PARSE);
|
||||
|
||||
static void
|
||||
gst_asf_parse_reset (GstAsfParse * asfparse)
|
||||
static gboolean
|
||||
gst_asf_parse_start (GstBaseParse * parse)
|
||||
{
|
||||
gst_adapter_clear (asfparse->adapter);
|
||||
GstAsfParse *asfparse = GST_ASF_PARSE_CAST (parse);
|
||||
gst_asf_file_info_reset (asfparse->asfinfo);
|
||||
asfparse->parse_state = ASF_PARSING_HEADERS;
|
||||
asfparse->headers_size = 0;
|
||||
asfparse->data_size = 0;
|
||||
asfparse->parsed_packets = 0;
|
||||
asfparse->offset = 0;
|
||||
|
||||
/* ASF Obj header length */
|
||||
gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (asfparse),
|
||||
ASF_GUID_OBJSIZE_SIZE);
|
||||
|
||||
gst_base_parse_set_syncable (GST_BASE_PARSE_CAST (asfparse), FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_asf_parse_sink_activate (GstPad * sinkpad, GstObject * parent)
|
||||
gst_asf_parse_stop (GstBaseParse * parse)
|
||||
{
|
||||
GstQuery *query;
|
||||
gboolean pull_mode;
|
||||
GstAsfParse *asfparse = GST_ASF_PARSE_CAST (parse);
|
||||
gst_asf_file_info_reset (asfparse->asfinfo);
|
||||
|
||||
query = gst_query_new_scheduling ();
|
||||
|
||||
if (!gst_pad_peer_query (sinkpad, query)) {
|
||||
gst_query_unref (query);
|
||||
goto activate_push;
|
||||
}
|
||||
|
||||
pull_mode = gst_query_has_scheduling_mode_with_flags (query,
|
||||
GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
|
||||
gst_query_unref (query);
|
||||
|
||||
if (!pull_mode)
|
||||
goto activate_push;
|
||||
|
||||
GST_DEBUG_OBJECT (sinkpad, "activating pull");
|
||||
return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
|
||||
|
||||
activate_push:
|
||||
{
|
||||
GST_DEBUG_OBJECT (sinkpad, "activating push");
|
||||
return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_asf_parse_sink_activate_mode (GstPad * pad, GstObject * parent,
|
||||
GstPadMode mode, gboolean active)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
switch (mode) {
|
||||
case GST_PAD_MODE_PULL:
|
||||
if (active) {
|
||||
res =
|
||||
gst_pad_start_task (pad, (GstTaskFunction) gst_asf_parse_loop, pad,
|
||||
NULL);
|
||||
} else {
|
||||
res = gst_pad_stop_task (pad);
|
||||
}
|
||||
case GST_PAD_MODE_PUSH:
|
||||
res = TRUE;
|
||||
break;
|
||||
default:
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_push (GstAsfParse * asfparse, GstBuffer * buf)
|
||||
{
|
||||
return gst_pad_push (asfparse->srcpad, buf);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_parse_data_object (GstAsfParse * asfparse, GstBuffer * buffer)
|
||||
gst_asf_parse_parse_data_object (GstAsfParse * asfparse, guint8 * data,
|
||||
gsize size)
|
||||
{
|
||||
GstByteReader *reader;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
guint64 packet_count = 0;
|
||||
GstMapInfo map;
|
||||
|
||||
GST_DEBUG_OBJECT (asfparse, "Parsing data object");
|
||||
|
||||
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
||||
reader = gst_byte_reader_new (map.data, map.size);
|
||||
reader = gst_byte_reader_new (data, size);
|
||||
/* skip to packet count */
|
||||
if (!gst_byte_reader_skip (reader, 40))
|
||||
goto error;
|
||||
|
@ -150,18 +97,241 @@ gst_asf_parse_parse_data_object (GstAsfParse * asfparse, GstBuffer * buffer)
|
|||
packet_count);
|
||||
}
|
||||
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
gst_byte_reader_free (reader);
|
||||
return gst_asf_parse_push (asfparse, buffer);
|
||||
return GST_FLOW_OK;
|
||||
|
||||
error:
|
||||
ret = GST_FLOW_ERROR;
|
||||
GST_ERROR_OBJECT (asfparse, "Error while parsing data object headers");
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
gst_byte_reader_free (reader);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* reads the next object and pushes it through without parsing */
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_handle_frame_push_object (GstAsfParse * asfparse,
|
||||
GstBaseParseFrame * frame, gint * skipsize, const Guid * guid)
|
||||
{
|
||||
GstBuffer *buffer = frame->buffer;
|
||||
GstMapInfo map;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
||||
if (map.size >= ASF_GUID_OBJSIZE_SIZE) {
|
||||
guint64 size;
|
||||
|
||||
size = gst_asf_match_and_peek_obj_size (map.data, guid);
|
||||
|
||||
if (size == 0) {
|
||||
GST_ERROR_OBJECT (asfparse, "GUID starting identifier missing");
|
||||
ret = GST_FLOW_ERROR;
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (size > map.size) {
|
||||
/* request all the obj data */
|
||||
gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (asfparse), size);
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
goto end;
|
||||
}
|
||||
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
|
||||
gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (asfparse),
|
||||
ASF_GUID_OBJSIZE_SIZE);
|
||||
gst_base_parse_finish_frame (GST_BASE_PARSE_CAST (asfparse), frame, size);
|
||||
} else {
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
*skipsize = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_handle_frame_headers (GstAsfParse * asfparse,
|
||||
GstBaseParseFrame * frame, gint * skipsize)
|
||||
{
|
||||
GstBuffer *buffer = frame->buffer;
|
||||
GstMapInfo map;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
||||
if (map.size >= ASF_GUID_OBJSIZE_SIZE) {
|
||||
guint64 size;
|
||||
|
||||
size = gst_asf_match_and_peek_obj_size (map.data,
|
||||
&(guids[ASF_HEADER_OBJECT_INDEX]));
|
||||
|
||||
if (size == 0) {
|
||||
GST_ERROR_OBJECT (asfparse, "ASF starting identifier missing");
|
||||
ret = GST_FLOW_ERROR;
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (size > map.size) {
|
||||
/* request all the obj data */
|
||||
gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (asfparse), size);
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (gst_asf_parse_headers_from_data (map.data, map.size, asfparse->asfinfo)) {
|
||||
GST_DEBUG_OBJECT (asfparse, "Successfully parsed headers");
|
||||
asfparse->parse_state = ASF_PARSING_DATA;
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
|
||||
GST_INFO_OBJECT (asfparse, "Broadcast mode %s",
|
||||
asfparse->asfinfo->broadcast ? "on" : "off");
|
||||
|
||||
gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (asfparse),
|
||||
ASF_GUID_OBJSIZE_SIZE);
|
||||
|
||||
gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (asfparse),
|
||||
gst_event_new_caps (gst_caps_new_simple ("video/x-ms-asf", "parsed",
|
||||
G_TYPE_BOOLEAN, TRUE, NULL)));
|
||||
gst_base_parse_finish_frame (GST_BASE_PARSE_CAST (asfparse), frame, size);
|
||||
} else {
|
||||
ret = GST_FLOW_ERROR;
|
||||
}
|
||||
} else {
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
*skipsize = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_handle_frame_data_header (GstAsfParse * asfparse,
|
||||
GstBaseParseFrame * frame, gint * skipsize)
|
||||
{
|
||||
GstBuffer *buffer = frame->buffer;
|
||||
GstMapInfo map;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
||||
if (map.size >= ASF_GUID_OBJSIZE_SIZE) {
|
||||
guint64 size;
|
||||
|
||||
size = gst_asf_match_and_peek_obj_size (map.data,
|
||||
&(guids[ASF_DATA_OBJECT_INDEX]));
|
||||
|
||||
if (size == 0) {
|
||||
GST_ERROR_OBJECT (asfparse, "ASF data object missing");
|
||||
ret = GST_FLOW_ERROR;
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ASF_DATA_OBJECT_SIZE > map.size) {
|
||||
/* request all the obj data header size */
|
||||
gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (asfparse),
|
||||
ASF_DATA_OBJECT_SIZE);
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (gst_asf_parse_parse_data_object (asfparse, map.data,
|
||||
map.size) == GST_FLOW_OK) {
|
||||
GST_DEBUG_OBJECT (asfparse, "Successfully parsed data object");
|
||||
asfparse->parse_state = ASF_PARSING_PACKETS;
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
|
||||
gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (asfparse),
|
||||
asfparse->asfinfo->packet_size);
|
||||
|
||||
gst_base_parse_finish_frame (GST_BASE_PARSE_CAST (asfparse), frame,
|
||||
ASF_DATA_OBJECT_SIZE);
|
||||
}
|
||||
} else {
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
*skipsize = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_handle_frame_packets (GstAsfParse * asfparse,
|
||||
GstBaseParseFrame * frame, gint * skipsize)
|
||||
{
|
||||
GstBuffer *buffer = frame->buffer;
|
||||
GstMapInfo map;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
|
||||
GST_LOG_OBJECT (asfparse, "Packet parsing");
|
||||
gst_buffer_map (buffer, &map, GST_MAP_READ);
|
||||
if (G_LIKELY (map.size >= asfparse->asfinfo->packet_size)) {
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
|
||||
GST_DEBUG_OBJECT (asfparse, "Parsing packet %" G_GUINT64_FORMAT,
|
||||
asfparse->parsed_packets);
|
||||
asfparse->parsed_packets++;
|
||||
gst_base_parse_finish_frame (GST_BASE_PARSE_CAST (asfparse), frame,
|
||||
asfparse->asfinfo->packet_size);
|
||||
|
||||
/* test if all packets have been processed */
|
||||
if (G_UNLIKELY (!asfparse->asfinfo->broadcast &&
|
||||
asfparse->parsed_packets == asfparse->asfinfo->packets_count)) {
|
||||
GST_INFO_OBJECT (asfparse,
|
||||
"All %" G_GUINT64_FORMAT " packets processed",
|
||||
asfparse->parsed_packets);
|
||||
asfparse->parse_state = ASF_PARSING_INDEXES;
|
||||
gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (asfparse),
|
||||
ASF_GUID_OBJSIZE_SIZE);
|
||||
}
|
||||
|
||||
} else {
|
||||
gst_base_parse_set_min_frame_size (GST_BASE_PARSE_CAST (asfparse),
|
||||
asfparse->asfinfo->packet_size);
|
||||
gst_buffer_unmap (buffer, &map);
|
||||
*skipsize = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_handle_frame_indexes (GstAsfParse * asfparse,
|
||||
GstBaseParseFrame * frame, gint * skipsize)
|
||||
{
|
||||
/* don't care about indexes, just push them forward */
|
||||
return gst_asf_parse_handle_frame_push_object (asfparse, frame, skipsize,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_handle_frame (GstBaseParse * parse,
|
||||
GstBaseParseFrame * frame, gint * skipsize)
|
||||
{
|
||||
GstAsfParse *asfparse = GST_ASF_PARSE_CAST (parse);
|
||||
|
||||
switch (asfparse->parse_state) {
|
||||
case ASF_PARSING_HEADERS:
|
||||
return gst_asf_parse_handle_frame_headers (asfparse, frame, skipsize);
|
||||
case ASF_PARSING_DATA:
|
||||
return gst_asf_parse_handle_frame_data_header (asfparse, frame, skipsize);
|
||||
case ASF_PARSING_PACKETS:
|
||||
return gst_asf_parse_handle_frame_packets (asfparse, frame, skipsize);
|
||||
case ASF_PARSING_INDEXES:
|
||||
return gst_asf_parse_handle_frame_indexes (asfparse, frame, skipsize);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_parse_packet (GstAsfParse * asfparse, GstBuffer * buffer)
|
||||
{
|
||||
|
@ -194,331 +364,12 @@ error:
|
|||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
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_pull_data_header (GstAsfParse * asfparse)
|
||||
{
|
||||
GstBuffer *buf = NULL;
|
||||
GstFlowReturn ret;
|
||||
|
||||
if ((ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset,
|
||||
ASF_DATA_OBJECT_SIZE, &buf)) != GST_FLOW_OK) {
|
||||
GST_ERROR_OBJECT (asfparse, "Failed to pull data header");
|
||||
return ret;
|
||||
}
|
||||
asfparse->offset += ASF_DATA_OBJECT_SIZE;
|
||||
asfparse->data_size = gst_asf_match_and_peek_obj_size_buf (buf,
|
||||
&(guids[ASF_DATA_OBJECT_INDEX]));
|
||||
if (asfparse->data_size == 0) {
|
||||
GST_ERROR_OBJECT (asfparse, "Unexpected object, was expecting data object");
|
||||
gst_buffer_unref (buf);
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
return gst_asf_parse_parse_data_object (asfparse, buf);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_pull_packets (GstAsfParse * asfparse)
|
||||
{
|
||||
GstFlowReturn ret;
|
||||
while (asfparse->asfinfo->broadcast ||
|
||||
asfparse->parsed_packets < asfparse->asfinfo->packets_count) {
|
||||
GstBuffer *packet;
|
||||
|
||||
GST_DEBUG_OBJECT (asfparse, "Parsing packet %" G_GUINT64_FORMAT,
|
||||
asfparse->parsed_packets);
|
||||
|
||||
/* get the packet */
|
||||
packet = NULL;
|
||||
ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset,
|
||||
asfparse->asfinfo->packet_size, &packet);
|
||||
if (ret != GST_FLOW_OK)
|
||||
return ret;
|
||||
asfparse->parsed_packets++;
|
||||
asfparse->offset += asfparse->asfinfo->packet_size;
|
||||
|
||||
/* parse the packet */
|
||||
ret = gst_asf_parse_parse_packet (asfparse, packet);
|
||||
if (ret != GST_FLOW_OK)
|
||||
return ret;
|
||||
}
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_asf_parse_pull_indexes (GstAsfParse * asfparse)
|
||||
{
|
||||
GstBuffer *guid_and_size;
|
||||
GstBuffer *buf;
|
||||
guint64 obj_size;
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
while (1) {
|
||||
guid_and_size = NULL;
|
||||
ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset,
|
||||
ASF_GUID_OBJSIZE_SIZE, &guid_and_size);
|
||||
if (ret != GST_FLOW_OK)
|
||||
break;
|
||||
/* we can peek at the object size */
|
||||
obj_size = gst_asf_match_and_peek_obj_size_buf (guid_and_size, NULL);
|
||||
if (obj_size == 0) {
|
||||
GST_ERROR_OBJECT (asfparse, "Incomplete object found");
|
||||
gst_buffer_unref (guid_and_size);
|
||||
ret = GST_FLOW_ERROR;
|
||||
break;
|
||||
}
|
||||
asfparse->offset += ASF_GUID_OBJSIZE_SIZE;
|
||||
|
||||
/* pull the rest of the object */
|
||||
buf = NULL;
|
||||
ret = gst_pad_pull_range (asfparse->sinkpad, asfparse->offset, obj_size,
|
||||
&buf);
|
||||
if (ret != GST_FLOW_OK) {
|
||||
gst_buffer_unref (guid_and_size);
|
||||
break;
|
||||
}
|
||||
asfparse->offset += obj_size - ASF_GUID_OBJSIZE_SIZE;
|
||||
|
||||
buf = gst_buffer_append (guid_and_size, buf);
|
||||
ret = gst_asf_parse_push (asfparse, buf);
|
||||
if (ret != GST_FLOW_OK)
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_asf_parse_loop (GstPad * pad)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstAsfParse *asfparse = GST_ASF_PARSE_CAST (GST_OBJECT_PARENT (pad));
|
||||
|
||||
GST_LOG_OBJECT (asfparse, "Processing data in loop function");
|
||||
switch (asfparse->parse_state) {
|
||||
case ASF_PARSING_HEADERS:
|
||||
GST_INFO_OBJECT (asfparse, "Starting to parse headers");
|
||||
ret = gst_asf_parse_pull_headers (asfparse);
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto pause;
|
||||
asfparse->parse_state = ASF_PARSING_DATA;
|
||||
|
||||
case ASF_PARSING_DATA:
|
||||
GST_INFO_OBJECT (asfparse, "Parsing data object headers");
|
||||
ret = gst_asf_parse_pull_data_header (asfparse);
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto pause;
|
||||
asfparse->parse_state = ASF_PARSING_PACKETS;
|
||||
|
||||
case ASF_PARSING_PACKETS:
|
||||
GST_INFO_OBJECT (asfparse, "Starting packet parsing");
|
||||
GST_INFO_OBJECT (asfparse, "Broadcast mode %s",
|
||||
asfparse->asfinfo->broadcast ? "on" : "off");
|
||||
ret = gst_asf_parse_pull_packets (asfparse);
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto pause;
|
||||
|
||||
/* test if all packets have been processed */
|
||||
if (!asfparse->asfinfo->broadcast &&
|
||||
asfparse->parsed_packets == asfparse->asfinfo->packets_count) {
|
||||
GST_INFO_OBJECT (asfparse,
|
||||
"All %" G_GUINT64_FORMAT " packets processed",
|
||||
asfparse->parsed_packets);
|
||||
asfparse->parse_state = ASF_PARSING_INDEXES;
|
||||
}
|
||||
|
||||
case ASF_PARSING_INDEXES:
|
||||
/* we currently don't care about indexes, so just push them forward */
|
||||
GST_INFO_OBJECT (asfparse, "Starting indexes parsing");
|
||||
ret = gst_asf_parse_pull_indexes (asfparse);
|
||||
if (ret != GST_FLOW_OK)
|
||||
goto pause;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pause:
|
||||
{
|
||||
const gchar *reason = gst_flow_get_name (ret);
|
||||
|
||||
GST_INFO_OBJECT (asfparse, "Pausing sinkpad task");
|
||||
gst_pad_pause_task (pad);
|
||||
|
||||
if (ret == GST_FLOW_EOS) {
|
||||
gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ());
|
||||
} else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
|
||||
GST_ELEMENT_ERROR (asfparse, STREAM, FAILED,
|
||||
(NULL), ("streaming task paused, reason %s (%d)", reason, ret));
|
||||
gst_pad_push_event (asfparse->srcpad, gst_event_new_eos ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
gst_asf_parse_finalize (GObject * object)
|
||||
{
|
||||
GstAsfParse *asfparse = GST_ASF_PARSE (object);
|
||||
gst_adapter_clear (asfparse->adapter);
|
||||
g_object_unref (G_OBJECT (asfparse->adapter));
|
||||
gst_caps_unref (asfparse->outcaps);
|
||||
gst_asf_file_info_free (asfparse->asfinfo);
|
||||
g_free (asfparse->packetinfo);
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
|
@ -529,16 +380,17 @@ gst_asf_parse_class_init (GstAsfParseClass * klass)
|
|||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseParseClass *gstbaseparse_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
gstbaseparse_class = (GstBaseParseClass *) klass;
|
||||
|
||||
gobject_class->finalize = gst_asf_parse_finalize;
|
||||
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_asf_parse_change_state);
|
||||
gstbaseparse_class->start = gst_asf_parse_start;
|
||||
gstbaseparse_class->stop = gst_asf_parse_stop;
|
||||
gstbaseparse_class->handle_frame = gst_asf_parse_handle_frame;
|
||||
|
||||
gst_element_class_add_pad_template (gstelement_class,
|
||||
gst_static_pad_template_get (&src_factory));
|
||||
|
@ -555,62 +407,8 @@ gst_asf_parse_class_init (GstAsfParseClass * klass)
|
|||
static void
|
||||
gst_asf_parse_init (GstAsfParse * asfparse)
|
||||
{
|
||||
asfparse->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
|
||||
gst_pad_set_chain_function (asfparse->sinkpad, gst_asf_parse_chain);
|
||||
gst_pad_set_activate_function (asfparse->sinkpad,
|
||||
gst_asf_parse_sink_activate);
|
||||
gst_pad_set_activatemode_function (asfparse->sinkpad,
|
||||
gst_asf_parse_sink_activate_mode);
|
||||
gst_element_add_pad (GST_ELEMENT (asfparse), asfparse->sinkpad);
|
||||
|
||||
asfparse->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
|
||||
gst_pad_use_fixed_caps (asfparse->srcpad);
|
||||
gst_element_add_pad (GST_ELEMENT (asfparse), asfparse->srcpad);
|
||||
|
||||
asfparse->adapter = gst_adapter_new ();
|
||||
asfparse->outcaps = gst_caps_new_empty_simple ("video/x-ms-asf");
|
||||
asfparse->asfinfo = gst_asf_file_info_new ();
|
||||
asfparse->packetinfo = g_new0 (GstAsfPacketInfo, 1);
|
||||
gst_asf_parse_reset (asfparse);
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_asf_parse_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstAsfParse *asfparse;
|
||||
GstStateChangeReturn ret;
|
||||
|
||||
asfparse = GST_ASF_PARSE (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
gst_asf_parse_reset (asfparse);
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE)
|
||||
goto done;
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstbaseparse.h>
|
||||
#include <gst/base/gstadapter.h>
|
||||
#include <gst/base/gstbytereader.h>
|
||||
|
||||
|
@ -54,29 +55,19 @@ typedef struct _GstAsfParse GstAsfParse;
|
|||
typedef struct _GstAsfParseClass GstAsfParseClass;
|
||||
|
||||
struct _GstAsfParse {
|
||||
GstElement element;
|
||||
GstBaseParse baseparse;
|
||||
|
||||
enum GstAsfParsingState parse_state;
|
||||
|
||||
GstAdapter *adapter;
|
||||
|
||||
GstPad *srcpad;
|
||||
GstPad *sinkpad;
|
||||
GstCaps *outcaps;
|
||||
|
||||
guint64 parsed_packets;
|
||||
|
||||
guint64 offset; /* used in pull mode */
|
||||
|
||||
/* parsed info */
|
||||
GstAsfFileInfo *asfinfo;
|
||||
GstAsfPacketInfo *packetinfo; /* we keep it here to avoid allocs */
|
||||
guint64 headers_size;
|
||||
guint64 data_size;
|
||||
GstAsfPacketInfo *packetinfo;
|
||||
};
|
||||
|
||||
struct _GstAsfParseClass {
|
||||
GstElementClass parent_class;
|
||||
GstBaseParseClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_asf_parse_get_type(void);
|
||||
|
|
Loading…
Reference in a new issue