static GstFlowReturn theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet, GstVideoCodecFrame * frame) { /* normal data packet */ th_ycbcr_buffer buf; gboolean keyframe; GstFlowReturn result; ogg_int64_t gp; if (G_UNLIKELY (!dec->have_header)) goto not_initialized; /* the second most significant bit of the first data byte is cleared * for keyframes. We can only check it if it's not a zero-length packet. */ keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0); if (G_UNLIKELY (keyframe)) { GST_DEBUG_OBJECT (dec, "we have a keyframe"); dec->need_keyframe = FALSE; } else if (G_UNLIKELY (dec->need_keyframe)) { goto dropping; } GST_DEBUG_OBJECT (dec, "parsing data packet"); /* this does the decoding */ if (G_UNLIKELY (th_decode_packetin (dec->decoder, packet, &gp) < 0)) goto decode_error; if (frame && (gst_video_decoder_get_max_decode_time (GST_VIDEO_DECODER (dec), frame) < 0)) goto dropping_qos; /* this does postprocessing and set up the decoded frame * pointers in our yuv variable */ if (G_UNLIKELY (th_decode_ycbcr_out (dec->decoder, buf) < 0)) goto no_yuv; if (G_UNLIKELY ((buf[0].width != dec->info.frame_width) || (buf[0].height != dec->info.frame_height))) goto wrong_dimensions; result = theora_handle_image (dec, buf, frame); return result; /* ERRORS */ not_initialized: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("no header sent yet")); return GST_FLOW_ERROR; } dropping: { GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe"); return GST_CUSTOM_FLOW_DROP; } dropping_qos: { GST_WARNING_OBJECT (dec, "dropping frame because of QoS"); return GST_CUSTOM_FLOW_DROP; } decode_error: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("theora decoder did not decode data packet")); return GST_FLOW_ERROR; } no_yuv: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("couldn't read out YUV image")); return GST_FLOW_ERROR; } wrong_dimensions: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT, (NULL), ("dimensions of image do not match header")); return GST_FLOW_ERROR; } }
static GstFlowReturn theora_handle_data_packet (GstTheoraDec * dec, ogg_packet * packet, GstClockTime outtime, GstClockTime outdur) { /* normal data packet */ th_ycbcr_buffer buf; GstBuffer *out; gboolean keyframe; GstFlowReturn result; ogg_int64_t gp; if (G_UNLIKELY (!dec->have_header)) goto not_initialized; /* get timestamp and durations */ if (outtime == -1) outtime = dec->last_timestamp; if (outdur == -1) outdur = gst_util_uint64_scale_int (GST_SECOND, dec->info.fps_denominator, dec->info.fps_numerator); /* calculate expected next timestamp */ if (outtime != -1 && outdur != -1) dec->last_timestamp = outtime + outdur; /* the second most significant bit of the first data byte is cleared * for keyframes. We can only check it if it's not a zero-length packet. */ keyframe = packet->bytes && ((packet->packet[0] & 0x40) == 0); if (G_UNLIKELY (keyframe)) { GST_DEBUG_OBJECT (dec, "we have a keyframe"); dec->need_keyframe = FALSE; } else if (G_UNLIKELY (dec->need_keyframe)) { goto dropping; } GST_DEBUG_OBJECT (dec, "parsing data packet"); /* this does the decoding */ if (G_UNLIKELY (th_decode_packetin (dec->decoder, packet, &gp) < 0)) goto decode_error; if (outtime != -1) { gboolean need_skip; GstClockTime running_time; GstClockTime earliest_time; gdouble proportion; /* qos needs to be done on running time */ running_time = gst_segment_to_running_time (&dec->segment, GST_FORMAT_TIME, outtime); GST_OBJECT_LOCK (dec); proportion = dec->proportion; earliest_time = dec->earliest_time; /* check for QoS, don't perform the last steps of getting and * pushing the buffers that are known to be late. */ need_skip = earliest_time != -1 && running_time <= earliest_time; GST_OBJECT_UNLOCK (dec); if (need_skip) { GstMessage *qos_msg; guint64 stream_time; gint64 jitter; GST_DEBUG_OBJECT (dec, "skipping decoding: qostime %" GST_TIME_FORMAT " <= %" GST_TIME_FORMAT, GST_TIME_ARGS (running_time), GST_TIME_ARGS (earliest_time)); dec->dropped++; stream_time = gst_segment_to_stream_time (&dec->segment, GST_FORMAT_TIME, outtime); jitter = GST_CLOCK_DIFF (running_time, earliest_time); qos_msg = gst_message_new_qos (GST_OBJECT_CAST (dec), FALSE, running_time, stream_time, outtime, outdur); gst_message_set_qos_values (qos_msg, jitter, proportion, 1000000); gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS, dec->processed, dec->dropped); gst_element_post_message (GST_ELEMENT_CAST (dec), qos_msg); goto dropping_qos; } } /* this does postprocessing and set up the decoded frame * pointers in our yuv variable */ if (G_UNLIKELY (th_decode_ycbcr_out (dec->decoder, buf) < 0)) goto no_yuv; if (G_UNLIKELY ((buf[0].width != dec->info.frame_width) || (buf[0].height != dec->info.frame_height))) goto wrong_dimensions; result = theora_handle_image (dec, buf, &out); if (result != GST_FLOW_OK) return result; GST_BUFFER_OFFSET (out) = dec->frame_nr; if (dec->frame_nr != -1) dec->frame_nr++; GST_BUFFER_OFFSET_END (out) = dec->frame_nr; GST_BUFFER_TIMESTAMP (out) = outtime; GST_BUFFER_DURATION (out) = outdur; dec->processed++; if (dec->segment.rate >= 0.0) result = theora_dec_push_forward (dec, out); else result = theora_dec_push_reverse (dec, out); return result; /* ERRORS */ not_initialized: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("no header sent yet")); return GST_FLOW_ERROR; } dropping: { GST_WARNING_OBJECT (dec, "dropping frame because we need a keyframe"); dec->discont = TRUE; return GST_FLOW_OK; } dropping_qos: { if (dec->frame_nr != -1) dec->frame_nr++; dec->discont = TRUE; GST_WARNING_OBJECT (dec, "dropping frame because of QoS"); return GST_FLOW_OK; } decode_error: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("theora decoder did not decode data packet")); return GST_FLOW_ERROR; } no_yuv: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("couldn't read out YUV image")); return GST_FLOW_ERROR; } wrong_dimensions: { GST_ELEMENT_ERROR (GST_ELEMENT (dec), STREAM, FORMAT, (NULL), ("dimensions of image do not match header")); return GST_FLOW_ERROR; } }