static gboolean gst_mpegv_parse_set_caps (GstBaseParse * parse, GstCaps * caps) { GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse); GstStructure *s; const GValue *value; GstBuffer *buf; GST_DEBUG_OBJECT (parse, "setcaps called with %" GST_PTR_FORMAT, caps); s = gst_caps_get_structure (caps, 0); if ((value = gst_structure_get_value (s, "codec_data")) != NULL && (buf = gst_value_get_buffer (value))) { GstMapInfo map; gst_buffer_map (buf, &map, GST_MAP_READ); /* best possible parse attempt, * src caps are based on sink caps so it will end up in there * whether sucessful or not */ mpvparse->seq_offset = 4; gst_mpegv_parse_process_config (mpvparse, &map, gst_buffer_get_size (buf)); gst_buffer_unmap (buf, &map); gst_mpegv_parse_reset_frame (mpvparse); } /* let's not interfere and accept regardless of config parsing success */ return TRUE; }
static void gst_mpegv_parse_reset (GstMpegvParse * mpvparse) { gst_mpegv_parse_reset_frame (mpvparse); mpvparse->profile = 0; mpvparse->update_caps = TRUE; gst_buffer_replace (&mpvparse->config, NULL); memset (&mpvparse->params, 0, sizeof (mpvparse->params)); }
static inline void update_frame_parsing_status (GstMpegvParse * mpvparse, GstBaseParseFrame * frame) { /* avoid stale cached parsing state */ if (frame->flags & GST_BASE_PARSE_FRAME_FLAG_NEW_FRAME) { GST_LOG_OBJECT (mpvparse, "parsing new frame"); gst_mpegv_parse_reset_frame (mpvparse); } else { GST_LOG_OBJECT (mpvparse, "resuming frame parsing"); } }
static void gst_mpegv_parse_reset (GstMpegvParse * mpvparse) { gst_mpegv_parse_reset_frame (mpvparse); mpvparse->profile = 0; mpvparse->update_caps = TRUE; mpvparse->send_codec_tag = TRUE; gst_buffer_replace (&mpvparse->config, NULL); memset (&mpvparse->sequencehdr, 0, sizeof (mpvparse->sequencehdr)); memset (&mpvparse->sequenceext, 0, sizeof (mpvparse->sequenceext)); memset (&mpvparse->pichdr, 0, sizeof (mpvparse->pichdr)); }
static void gst_mpegv_parse_reset (GstMpegvParse * mpvparse) { gst_mpegv_parse_reset_frame (mpvparse); mpvparse->profile = 0; mpvparse->update_caps = TRUE; mpvparse->send_codec_tag = TRUE; mpvparse->send_mpeg_meta = TRUE; gst_buffer_replace (&mpvparse->config, NULL); memset (&mpvparse->sequencehdr, 0, sizeof (mpvparse->sequencehdr)); memset (&mpvparse->sequenceext, 0, sizeof (mpvparse->sequenceext)); memset (&mpvparse->sequencedispext, 0, sizeof (mpvparse->sequencedispext)); memset (&mpvparse->pichdr, 0, sizeof (mpvparse->pichdr)); memset (&mpvparse->picext, 0, sizeof (mpvparse->picext)); mpvparse->seqhdr_updated = FALSE; mpvparse->seqext_updated = FALSE; mpvparse->seqdispext_updated = FALSE; mpvparse->picext_updated = FALSE; mpvparse->quantmatrext_updated = FALSE; }
static GstFlowReturn gst_mpegv_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { GstMpegvParse *mpvparse = GST_MPEGVIDEO_PARSE (parse); GstBuffer *buf = frame->buffer; gboolean ret = FALSE; gint off = 0; GstMpegVideoPacket packet; guint8 *data; gint size; GstMapInfo map; update_frame_parsing_status (mpvparse, frame); gst_buffer_map (buf, &map, GST_MAP_READ); data = map.data; size = map.size; retry: /* at least start code and subsequent byte */ if (G_UNLIKELY (size < 5 + off)) goto exit; /* if already found a previous start code, e.g. start of frame, go for next */ if (mpvparse->last_sc >= 0) { off = packet.offset = mpvparse->last_sc; packet.size = 0; goto next; } if (!gst_mpeg_video_parse (&packet, data, size, off)) { /* didn't find anything that looks like a sync word, skip */ GST_LOG_OBJECT (mpvparse, "no start code found"); *skipsize = size - 3; goto exit; } off = packet.offset - 4; GST_LOG_OBJECT (mpvparse, "possible sync at buffer offset %d", off); /* possible frame header, but not at offset 0? skip bytes before sync */ if (G_UNLIKELY (off > 0)) { *skipsize = off; goto exit; } /* note: initial start code is assumed at offset 0 by subsequent code */ /* examine start code, see if it looks like an initial start code */ if (gst_mpegv_parse_process_sc (mpvparse, buf, 4, packet.type)) { /* found sc */ GST_LOG_OBJECT (mpvparse, "valid start code found"); mpvparse->last_sc = 0; } else { off++; gst_mpegv_parse_reset_frame (mpvparse); GST_LOG_OBJECT (mpvparse, "invalid start code"); goto retry; } next: /* start is fine as of now */ *skipsize = 0; /* terminating start code may have been found in prev scan already */ if (((gint) packet.size) >= 0) { off = packet.offset + packet.size; /* so now we have start code at start of data; locate next start code */ if (!gst_mpeg_video_parse (&packet, data, size, off)) { off = -1; } else { g_assert (packet.offset >= 4); off = packet.offset - 4; } } else { off = -1; } GST_LOG_OBJECT (mpvparse, "next start code at %d", off); if (off < 0) { /* if draining, take all */ if (GST_BASE_PARSE_DRAINING (parse)) { GST_LOG_OBJECT (mpvparse, "draining, accepting all data"); off = size; ret = TRUE; } else { GST_LOG_OBJECT (mpvparse, "need more data"); /* resume scan where we left it */ mpvparse->last_sc = size - 3; /* request best next available */ off = G_MAXUINT; goto exit; } } else { /* decide whether this startcode ends a frame */ ret = gst_mpegv_parse_process_sc (mpvparse, buf, off + 4, packet.type); } if (!ret) goto next; exit: gst_buffer_unmap (buf, &map); if (ret) { GstFlowReturn res; *skipsize = 0; g_assert (off <= map.size); res = gst_mpegv_parse_parse_frame (parse, frame); if (res == GST_BASE_PARSE_FLOW_DROPPED) frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP; return gst_base_parse_finish_frame (parse, frame, off); } return GST_FLOW_OK; }