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; }
/* for off == 4 initial code; returns TRUE if code starts a frame * otherwise returns TRUE if code terminates preceding frame */ static gboolean gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse, GstBuffer * buf, gint off, guint8 code) { gboolean ret = FALSE, packet = TRUE; g_return_val_if_fail (buf && gst_buffer_get_size (buf) >= 4, FALSE); GST_LOG_OBJECT (mpvparse, "process startcode %x (%s)", code, picture_start_code_name (code)); switch (code) { case GST_MPEG_VIDEO_PACKET_PICTURE: GST_LOG_OBJECT (mpvparse, "startcode is PICTURE"); /* picture is aggregated with preceding sequence/gop, if any. * so, picture start code only ends if already a previous one */ if (mpvparse->pic_offset < 0) mpvparse->pic_offset = off; else ret = (off != mpvparse->pic_offset); /* but it's a valid starting one */ if (off == 4) ret = TRUE; break; case GST_MPEG_VIDEO_PACKET_SEQUENCE: GST_LOG_OBJECT (mpvparse, "startcode is SEQUENCE"); if (mpvparse->seq_offset < 0) mpvparse->seq_offset = off; ret = TRUE; break; case GST_MPEG_VIDEO_PACKET_GOP: GST_LOG_OBJECT (mpvparse, "startcode is GOP"); if (mpvparse->seq_offset >= 0) ret = mpvparse->gop_split; else ret = TRUE; break; case GST_MPEG_VIDEO_PACKET_EXTENSION: GST_LOG_OBJECT (mpvparse, "startcode is VIDEO PACKET EXTENSION"); parse_picture_extension (mpvparse, buf, off); if (mpvparse->ext_count < G_N_ELEMENTS (mpvparse->ext_offsets)) mpvparse->ext_offsets[mpvparse->ext_count++] = off; /* fall-through */ default: packet = FALSE; break; } /* set size to avoid processing config again */ if (mpvparse->seq_offset >= 0 && off != mpvparse->seq_offset && !mpvparse->seq_size && packet) { /* should always be at start */ g_assert (mpvparse->seq_offset <= 4); gst_mpegv_parse_process_config (mpvparse, buf, off - mpvparse->seq_offset); mpvparse->seq_size = off - mpvparse->seq_offset; } /* extract some picture info if there is any in the frame being terminated */ if (ret && mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off) { GstMapInfo map; gst_buffer_map (buf, &map, GST_MAP_READ); if (gst_mpeg_video_parse_picture_header (&mpvparse->pichdr, map.data, map.size, mpvparse->pic_offset)) GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s), ending" "frame of size %d", mpvparse->pichdr.pic_type, picture_type_name (mpvparse->pichdr.pic_type), off - 4); else GST_LOG_OBJECT (mpvparse, "Couldn't parse picture at offset %d", mpvparse->pic_offset); gst_buffer_unmap (buf, &map); } return ret; }
/* for off == 0 initial code; returns TRUE if code starts a frame, * otherwise returns TRUE if code terminates preceding frame */ static gboolean gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse, GstBuffer * buf, gint off) { gboolean ret = FALSE, do_seq = TRUE; guint8 *data; guint code; g_return_val_if_fail (buf && GST_BUFFER_SIZE (buf) >= 4, FALSE); data = GST_BUFFER_DATA (buf); code = data[off + 3]; GST_LOG_OBJECT (mpvparse, "process startcode %x (%s)", code, picture_start_code_name (code)); switch (code) { case MPEG_PACKET_PICTURE: GST_LOG_OBJECT (mpvparse, "startcode is PICTURE"); /* picture is aggregated with preceding sequence/gop, if any. * so, picture start code only ends if already a previous one */ if (mpvparse->pic_offset < 0) mpvparse->pic_offset = off; else ret = TRUE; if (!off) ret = TRUE; break; case MPEG_PACKET_SEQUENCE: GST_LOG_OBJECT (mpvparse, "startcode is SEQUENCE"); if (off == 0) mpvparse->seq_offset = off; ret = TRUE; break; case MPEG_PACKET_GOP: GST_LOG_OBJECT (mpvparse, "startcode is GOP"); if (mpvparse->seq_offset >= 0) ret = mpvparse->gop_split; else ret = TRUE; break; default: do_seq = FALSE; break; } /* process config data */ if (G_UNLIKELY (mpvparse->seq_offset >= 0 && off && do_seq)) { g_assert (mpvparse->seq_offset == 0); gst_mpegv_parse_process_config (mpvparse, GST_BUFFER_DATA (buf), off); /* avoid accepting again for a PICTURE sc following a GOP sc */ mpvparse->seq_offset = -1; } /* extract some picture info if there is any in the frame being terminated */ if (G_UNLIKELY (ret && off)) { if (G_LIKELY (mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off)) { if (G_LIKELY (GST_BUFFER_SIZE (buf) >= mpvparse->pic_offset + 6)) { gint pct = (data[mpvparse->pic_offset + 5] >> 3) & 0x7; GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s)", pct, picture_type_name (pct)); mpvparse->intra_frame = (pct == MPEG_PICTURE_TYPE_I); } else { GST_WARNING_OBJECT (mpvparse, "no data following PICTURE startcode"); mpvparse->intra_frame = FALSE; } } else {
/* for off == 4 initial code; returns TRUE if code starts a frame * otherwise returns TRUE if code terminates preceding frame */ static gboolean gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse, GstMapInfo * info, gint off, GstMpegVideoPacket * packet) { gboolean ret = FALSE, checkconfig = TRUE; GST_LOG_OBJECT (mpvparse, "process startcode %x (%s) offset:%d", packet->type, picture_start_code_name (packet->type), off); switch (packet->type) { case GST_MPEG_VIDEO_PACKET_PICTURE: GST_LOG_OBJECT (mpvparse, "startcode is PICTURE"); /* picture is aggregated with preceding sequence/gop, if any. * so, picture start code only ends if already a previous one */ if (mpvparse->pic_offset < 0) mpvparse->pic_offset = off; else ret = (off != mpvparse->pic_offset); /* but it's a valid starting one */ if (off == 4) ret = TRUE; break; case GST_MPEG_VIDEO_PACKET_SEQUENCE: GST_LOG_OBJECT (mpvparse, "startcode is SEQUENCE"); if (mpvparse->seq_offset < 0) mpvparse->seq_offset = off; ret = TRUE; break; case GST_MPEG_VIDEO_PACKET_GOP: GST_LOG_OBJECT (mpvparse, "startcode is GOP"); if (mpvparse->seq_offset >= 0) ret = mpvparse->gop_split; else ret = TRUE; break; case GST_MPEG_VIDEO_PACKET_EXTENSION: GST_LOG_OBJECT (mpvparse, "startcode is VIDEO PACKET EXTENSION"); parse_packet_extension (mpvparse, info, off); if (mpvparse->ext_count < G_N_ELEMENTS (mpvparse->ext_offsets)) mpvparse->ext_offsets[mpvparse->ext_count++] = off; checkconfig = FALSE; break; default: if (GST_MPEG_VIDEO_PACKET_IS_SLICE (packet->type)) { mpvparse->slice_count++; if (mpvparse->slice_offset == 0) mpvparse->slice_offset = off - 4; } checkconfig = FALSE; break; } /* set size to avoid processing config again */ if (checkconfig && mpvparse->seq_offset >= 0 && off != mpvparse->seq_offset && !mpvparse->seq_size) { /* should always be at start */ g_assert (mpvparse->seq_offset <= 4); gst_mpegv_parse_process_config (mpvparse, info, off - mpvparse->seq_offset); mpvparse->seq_size = off - mpvparse->seq_offset; } /* extract some picture info if there is any in the frame being terminated */ if (ret && mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off) { GstMpegVideoPacket header; header.data = info->data; header.type = GST_MPEG_VIDEO_PACKET_PICTURE; header.offset = mpvparse->pic_offset; header.size = info->size - mpvparse->pic_offset; if (gst_mpeg_video_packet_parse_picture_header (&header, &mpvparse->pichdr)) GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s), ending" "frame of size %d", mpvparse->pichdr.pic_type, picture_type_name (mpvparse->pichdr.pic_type), off - 4); else GST_LOG_OBJECT (mpvparse, "Couldn't parse picture at offset %d", mpvparse->pic_offset); } return ret; }