static gboolean gst_dvdec_src_negotiate (GstDVDec * dvdec) { GstCaps *othercaps; gboolean ret; /* no PAR was specified in input, derive from encoded data */ if (dvdec->need_par) { if (dvdec->PAL) { if (dvdec->wide) { dvdec->par_x = PAL_WIDE_PAR_X; dvdec->par_y = PAL_WIDE_PAR_Y; } else { dvdec->par_x = PAL_NORMAL_PAR_X; dvdec->par_y = PAL_NORMAL_PAR_Y; } } else { if (dvdec->wide) { dvdec->par_x = NTSC_WIDE_PAR_X; dvdec->par_y = NTSC_WIDE_PAR_Y; } else { dvdec->par_x = NTSC_NORMAL_PAR_X; dvdec->par_y = NTSC_NORMAL_PAR_Y; } } GST_DEBUG_OBJECT (dvdec, "Inferred PAR %d/%d from video format", dvdec->par_x, dvdec->par_y); } /* ignoring rgb, bgr0 for now */ dvdec->bpp = 2; gst_video_info_set_format (&dvdec->vinfo, GST_VIDEO_FORMAT_YUY2, 720, dvdec->height); dvdec->vinfo.fps_n = dvdec->framerate_numerator; dvdec->vinfo.fps_d = dvdec->framerate_denominator; dvdec->vinfo.par_n = dvdec->par_x; dvdec->vinfo.par_d = dvdec->par_y; if (dvdec->interlaced) { dvdec->vinfo.interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED; } else { dvdec->vinfo.interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; } othercaps = gst_video_info_to_caps (&dvdec->vinfo); ret = gst_pad_set_caps (dvdec->srcpad, othercaps); gst_dvdec_negotiate_pool (dvdec, othercaps, &dvdec->vinfo); gst_caps_unref (othercaps); dvdec->src_negotiated = TRUE; return ret; }
static GstFlowReturn gst_dvdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstDVDec *dvdec; guint8 *inframe; guint8 *outframe_ptrs[3]; gint outframe_pitches[3]; GstMapInfo map; GstVideoFrame frame; GstBuffer *outbuf; GstFlowReturn ret = GST_FLOW_OK; guint length; guint64 cstart = GST_CLOCK_TIME_NONE, cstop = GST_CLOCK_TIME_NONE; gboolean PAL, wide; dvdec = GST_DVDEC (parent); gst_buffer_map (buf, &map, GST_MAP_READ); inframe = map.data; /* buffer should be at least the size of one NTSC frame, this should * be enough to decode the header. */ if (G_UNLIKELY (map.size < NTSC_BUFFER)) goto wrong_size; /* preliminary dropping. unref and return if outside of configured segment */ if ((dvdec->segment.format == GST_FORMAT_TIME) && (!(gst_segment_clip (&dvdec->segment, GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf), GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf), &cstart, &cstop)))) goto dropping; if (G_UNLIKELY (dv_parse_header (dvdec->decoder, inframe) < 0)) goto parse_header_error; /* get size */ PAL = dv_system_50_fields (dvdec->decoder); wide = dv_format_wide (dvdec->decoder); /* check the buffer is of right size after we know if we are * dealing with PAL or NTSC */ length = (PAL ? PAL_BUFFER : NTSC_BUFFER); if (G_UNLIKELY (map.size < length)) goto wrong_size; dv_parse_packs (dvdec->decoder, inframe); if (dvdec->video_offset % dvdec->drop_factor != 0) goto skip; /* renegotiate on change */ if (PAL != dvdec->PAL || wide != dvdec->wide) { dvdec->src_negotiated = FALSE; dvdec->PAL = PAL; dvdec->wide = wide; } dvdec->height = (dvdec->PAL ? PAL_HEIGHT : NTSC_HEIGHT); dvdec->interlaced = !dv_is_progressive (dvdec->decoder); /* negotiate if not done yet */ if (!dvdec->src_negotiated) { if (!gst_dvdec_src_negotiate (dvdec)) goto not_negotiated; } if (gst_pad_check_reconfigure (dvdec->srcpad)) { GstCaps *caps; caps = gst_pad_get_current_caps (dvdec->srcpad); if (!caps) goto not_negotiated; gst_dvdec_negotiate_pool (dvdec, caps, &dvdec->vinfo); gst_caps_unref (caps); } if (dvdec->need_segment) { gst_pad_push_event (dvdec->srcpad, gst_event_new_segment (&dvdec->segment)); dvdec->need_segment = FALSE; } ret = gst_buffer_pool_acquire_buffer (dvdec->pool, &outbuf, NULL); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto no_buffer; gst_video_frame_map (&frame, &dvdec->vinfo, outbuf, GST_MAP_WRITE); outframe_ptrs[0] = GST_VIDEO_FRAME_COMP_DATA (&frame, 0); outframe_pitches[0] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 0); /* the rest only matters for YUY2 */ if (dvdec->bpp < 3) { outframe_ptrs[1] = GST_VIDEO_FRAME_COMP_DATA (&frame, 1); outframe_ptrs[2] = GST_VIDEO_FRAME_COMP_DATA (&frame, 2); outframe_pitches[1] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 1); outframe_pitches[2] = GST_VIDEO_FRAME_COMP_STRIDE (&frame, 2); } GST_DEBUG_OBJECT (dvdec, "decoding and pushing buffer"); dv_decode_full_frame (dvdec->decoder, inframe, e_dv_color_yuv, outframe_ptrs, outframe_pitches); gst_video_frame_unmap (&frame); GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF); GST_BUFFER_OFFSET (outbuf) = GST_BUFFER_OFFSET (buf); GST_BUFFER_OFFSET_END (outbuf) = GST_BUFFER_OFFSET_END (buf); /* FIXME : Compute values when using non-TIME segments, * but for the moment make sure we at least don't set bogus values */ if (GST_CLOCK_TIME_IS_VALID (cstart)) { GST_BUFFER_TIMESTAMP (outbuf) = cstart; if (GST_CLOCK_TIME_IS_VALID (cstop)) GST_BUFFER_DURATION (outbuf) = cstop - cstart; } ret = gst_pad_push (dvdec->srcpad, outbuf); skip: dvdec->video_offset++; done: gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); return ret; /* ERRORS */ wrong_size: { GST_ELEMENT_ERROR (dvdec, STREAM, DECODE, (NULL), ("Input buffer too small")); ret = GST_FLOW_ERROR; goto done; } parse_header_error: { GST_ELEMENT_ERROR (dvdec, STREAM, DECODE, (NULL), ("Error parsing DV header")); ret = GST_FLOW_ERROR; goto done; } not_negotiated: { GST_DEBUG_OBJECT (dvdec, "could not negotiate output"); ret = GST_FLOW_NOT_NEGOTIATED; goto done; } no_buffer: { GST_DEBUG_OBJECT (dvdec, "could not allocate buffer"); goto done; } dropping: { GST_DEBUG_OBJECT (dvdec, "dropping buffer since it's out of the configured segment"); goto done; } }