diff options
-rw-r--r-- | ext/openh264/gstopenh264dec.cpp | 100 |
1 files changed, 57 insertions, 43 deletions
diff --git a/ext/openh264/gstopenh264dec.cpp b/ext/openh264/gstopenh264dec.cpp index 303ce87dd..d4b2da88e 100644 --- a/ext/openh264/gstopenh264dec.cpp +++ b/ext/openh264/gstopenh264dec.cpp @@ -206,78 +206,92 @@ gst_openh264dec_handle_frame (GstVideoDecoder * decoder, guint i; guint8 *p; guint row_stride, component_width, component_height, src_width, row; - gboolean at_eos = (frame == NULL); - if (frame) { + if (frame == NULL) { +#if OPENH264_VERSION_CHECK (1,9) + /* Called with no videoframe for EOS logic. Drain out */ + int end_of_stream = 1; + memset (&dst_buf_info, 0, sizeof (SBufferInfo)); + + openh264dec->decoder->SetOption (DECODER_OPTION_END_OF_STREAM, + &end_of_stream); + ret = openh264dec->decoder->FlushFrame (yuvdata, &dst_buf_info); + + if (ret != dsErrorFree || dst_buf_info.iBufferStatus != 1) { + GST_DEBUG_OBJECT (decoder, "No more frames to retrieve at EOS"); + return GST_FLOW_EOS; + } +#else + return GST_FLOW_EOS; +#endif + } else { if (!gst_buffer_map (frame->input_buffer, &map_info, GST_MAP_READ)) { GST_ERROR_OBJECT (openh264dec, "Cannot map input buffer!"); gst_video_codec_frame_unref (frame); return GST_FLOW_ERROR; } - GST_LOG_OBJECT (openh264dec, "handle frame, %d", + GST_LOG_OBJECT (openh264dec, "handle frame, 1st NAL type %d", map_info.size > 4 ? map_info.data[4] & 0x1f : -1); memset (&dst_buf_info, 0, sizeof (SBufferInfo)); + /* Use the unsigned long long OpenH264 timestamp to store the system_frame_number + * to track the original frame through any OpenH264 reordering */ + dst_buf_info.uiInBsTimeStamp = frame->system_frame_number; + + GST_LOG_OBJECT (decoder, "Submitting frame with PTS %" GST_TIME_FORMAT + " and frame ref %" G_GUINT64_FORMAT, + GST_TIME_ARGS (frame->pts), (guint64) frame->system_frame_number); + ret = openh264dec->decoder->DecodeFrame2 (map_info.data, map_info.size, yuvdata, &dst_buf_info); + gst_buffer_unmap (frame->input_buffer, &map_info); - if (ret == dsNoParamSets) { + if (ret != dsErrorFree) { + /* Request a key unit from upstream */ GST_DEBUG_OBJECT (openh264dec, "Requesting a key unit"); gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decoder), gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, FALSE, 0)); - } - if (ret != dsErrorFree && ret != dsNoParamSets) { - GST_DEBUG_OBJECT (openh264dec, "Requesting a key unit"); - gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decoder), - gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE, - FALSE, 0)); GST_LOG_OBJECT (openh264dec, "error decoding nal, return code: %d", ret); - } + gst_video_codec_frame_unref (frame); - gst_buffer_unmap (frame->input_buffer, &map_info); - if (ret != dsErrorFree) - return gst_video_decoder_drop_frame (decoder, frame); + /* Get back the frame that was reported as errored */ + frame = + gst_video_decoder_get_frame (decoder, dst_buf_info.uiOutYuvTimeStamp); + if (frame) { + GST_LOG_OBJECT (decoder, + "Dropping errored frame ref %" G_GUINT64_FORMAT, + (guint64) dst_buf_info.uiOutYuvTimeStamp); + return gst_video_decoder_drop_frame (decoder, frame); + } + return GST_FLOW_OK; + } gst_video_codec_frame_unref (frame); frame = NULL; - } else { - memset (&dst_buf_info, 0, sizeof (SBufferInfo)); - ret = openh264dec->decoder->DecodeFrame2 (NULL, 0, yuvdata, &dst_buf_info); - if (ret != dsErrorFree) { - return GST_FLOW_EOS; + + /* No output available yet */ + if (dst_buf_info.iBufferStatus != 1) { + GST_LOG_OBJECT (decoder, "No buffer decoded yet"); + return GST_FLOW_OK; } } - /* No output available yet */ - if (dst_buf_info.iBufferStatus != 1) { - if (at_eos) - return GST_FLOW_EOS; - - gst_video_codec_frame_unref (frame); - return GST_FLOW_OK; - } + GST_LOG_OBJECT (decoder, "Got back frame with frame ref %" G_GUINT64_FORMAT, + (guint64) dst_buf_info.uiOutYuvTimeStamp); - /* FIXME: openh264 has no way for us to get a connection - * between the input and output frames, we just have to - * guess based on the input. Fortunately openh264 can - * only do baseline profile. */ - frame = gst_video_decoder_get_oldest_frame (decoder); + /* OpenH264 lets us pass an int reference through + * so we can retrieve the input frame now */ + frame = gst_video_decoder_get_frame (decoder, dst_buf_info.uiOutYuvTimeStamp); if (!frame) { - /* Can only happen in finish() */ - return GST_FLOW_EOS; - } - - { - GstClockTime pts = dst_buf_info.uiOutYuvTimeStamp; - if (pts != frame->pts) { - GST_DEBUG_OBJECT (decoder, "Got output PTS %" GST_TIME_FORMAT - " but expected %" GST_TIME_FORMAT, GST_TIME_ARGS (pts), - GST_TIME_ARGS (frame->pts)); - } + /* Where did our frame go? This is a reference tracking error. */ + GST_WARNING_OBJECT (decoder, + "Failed to look up frame ref %" G_GUINT64_FORMAT, + (guint64) dst_buf_info.uiOutYuvTimeStamp); + return GST_FLOW_OK; } actual_width = dst_buf_info.UsrData.sSystemBuffer.iWidth; |