LIBDE265_API de265_error de265_decode_data(de265_decoder_context* de265ctx, const void* data8, int len) { //decoder_context* ctx = (decoder_context*)de265ctx; de265_error err; if (len > 0) { err = de265_push_data(de265ctx, data8, len, 0, NULL); } else { err = de265_flush_data(de265ctx); } if (err != DE265_OK) { return err; } int more = 0; do { err = de265_decode(de265ctx, &more); if (err != DE265_OK) { more = 0; } switch (err) { case DE265_ERROR_WAITING_FOR_INPUT_DATA: // ignore error (didn't exist in 0.4 and before) err = DE265_OK; break; default: break; } } while (more); return err; }
static gboolean gst_libde265_dec_flush (GstVideoDecoder * decoder) { GstLibde265Dec *dec = GST_LIBDE265_DEC (decoder); de265_reset (dec->ctx); dec->buffer_full = 0; if (dec->codec_data != NULL && dec->format == GST_TYPE_LIBDE265_FORMAT_BYTESTREAM) { int more; de265_error err = de265_push_data (dec->ctx, dec->codec_data, dec->codec_data_size, 0, NULL); if (!de265_isOK (err)) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Failed to push codec data: %s (code=%d)", de265_get_error_text (err), err), (NULL)); return FALSE; } de265_push_end_of_NAL (dec->ctx); do { err = de265_decode (dec->ctx, &more); switch (err) { case DE265_OK: break; case DE265_ERROR_IMAGE_BUFFER_FULL: case DE265_ERROR_WAITING_FOR_INPUT_DATA: /* not really an error */ more = 0; break; default: if (!de265_isOK (err)) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Failed to decode codec data: %s (code=%d)", de265_get_error_text (err), err), (NULL)); return FALSE; } } } while (more); } return TRUE; }
static GstFlowReturn gst_libde265_dec_handle_frame (GstVideoDecoder * decoder, GstVideoCodecFrame * frame) { GstLibde265Dec *dec = GST_LIBDE265_DEC (decoder); uint8_t *frame_data; uint8_t *end_data; const struct de265_image *img; de265_error ret = DE265_OK; int more = 0; GstClockTime pts; gsize size; GstMapInfo info; pts = frame->pts; if (pts == GST_CLOCK_TIME_NONE) { pts = frame->dts; } if (!gst_buffer_map (frame->input_buffer, &info, GST_MAP_READ)) { GST_ERROR_OBJECT (dec, "Failed to map input buffer"); return GST_FLOW_ERROR; } frame_data = info.data; size = info.size; end_data = frame_data + size; if (size > 0) { if (dec->format == GST_TYPE_LIBDE265_FORMAT_PACKETIZED) { /* stream contains length fields and NALs */ uint8_t *start_data = frame_data; while (start_data + dec->length_size <= end_data) { int nal_size = 0; int i; for (i = 0; i < dec->length_size; i++) { nal_size = (nal_size << 8) | start_data[i]; } if (start_data + dec->length_size + nal_size > end_data) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Overflow in input data, check stream format"), (NULL)); goto error_input; } ret = de265_push_NAL (dec->ctx, start_data + dec->length_size, nal_size, (de265_PTS) pts, (void *) (uintptr_t) (frame->system_frame_number + 1)); if (ret != DE265_OK) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Error while pushing data: %s (code=%d)", de265_get_error_text (ret), ret), (NULL)); goto error_input; } start_data += dec->length_size + nal_size; } } else { ret = de265_push_data (dec->ctx, frame_data, size, (de265_PTS) pts, (void *) (uintptr_t) (frame->system_frame_number + 1)); if (ret != DE265_OK) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Error while pushing data: %s (code=%d)", de265_get_error_text (ret), ret), (NULL)); goto error_input; } } } else { ret = de265_flush_data (dec->ctx); if (ret != DE265_OK) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Error while flushing data: %s (code=%d)", de265_get_error_text (ret), ret), (NULL)); goto error_input; } } gst_buffer_unmap (frame->input_buffer, &info); /* decode as much as possible */ do { ret = de265_decode (dec->ctx, &more); } while (more && ret == DE265_OK); switch (ret) { case DE265_OK: case DE265_ERROR_WAITING_FOR_INPUT_DATA: break; case DE265_ERROR_IMAGE_BUFFER_FULL: dec->buffer_full = 1; if ((img = de265_peek_next_picture (dec->ctx)) == NULL) { return GST_FLOW_OK; } break; default: GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Error while decoding: %s (code=%d)", de265_get_error_text (ret), ret), (NULL)); return GST_FLOW_ERROR; } while ((ret = de265_get_warning (dec->ctx)) != DE265_OK) { GST_ELEMENT_WARNING (decoder, STREAM, DECODE, ("%s (code=%d)", de265_get_error_text (ret), ret), (NULL)); } img = de265_get_next_picture (dec->ctx); if (img == NULL) { /* need more data */ return GST_FLOW_OK; } return _gst_libde265_return_image (decoder, frame, img); error_input: gst_buffer_unmap (frame->input_buffer, &info); return GST_FLOW_ERROR; }
static gboolean gst_libde265_dec_set_format (GstVideoDecoder * decoder, GstVideoCodecState * state) { GstLibde265Dec *dec = GST_LIBDE265_DEC (decoder); if (dec->input_state != NULL) { gst_video_codec_state_unref (dec->input_state); } dec->input_state = state; if (state != NULL) { gst_video_codec_state_ref (state); } if (state != NULL && state->caps != NULL) { GstStructure *str; const GValue *value; str = gst_caps_get_structure (state->caps, 0); if ((value = gst_structure_get_value (str, "codec_data"))) { GstMapInfo info; guint8 *data; gsize size; GstBuffer *buf; de265_error err; int more; buf = gst_value_get_buffer (value); if (!gst_buffer_map (buf, &info, GST_MAP_READ)) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Failed to map codec data"), (NULL)); return FALSE; } data = info.data; size = info.size; free (dec->codec_data); dec->codec_data = malloc (size); g_assert (dec->codec_data != NULL); dec->codec_data_size = size; memcpy (dec->codec_data, data, size); if (size > 3 && (data[0] || data[1] || data[2] > 1)) { /* encoded in "hvcC" format (assume version 0) */ dec->format = GST_TYPE_LIBDE265_FORMAT_PACKETIZED; if (size > 22) { int i; int num_param_sets; int pos; if (data[0] != 0) { GST_ELEMENT_WARNING (decoder, STREAM, DECODE, ("Unsupported extra data version %d, decoding may fail", data[0]), (NULL)); } dec->length_size = (data[21] & 3) + 1; num_param_sets = data[22]; pos = 23; for (i = 0; i < num_param_sets; i++) { int j; int nal_count; if (pos + 3 > size) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Buffer underrun in extra header (%d >= %" G_GSIZE_FORMAT ")", pos + 3, size), (NULL)); return FALSE; } /* ignore flags + NAL type (1 byte) */ nal_count = data[pos + 1] << 8 | data[pos + 2]; pos += 3; for (j = 0; j < nal_count; j++) { int nal_size; if (pos + 2 > size) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Buffer underrun in extra nal header (%d >= %" G_GSIZE_FORMAT ")", pos + 2, size), (NULL)); return FALSE; } nal_size = data[pos] << 8 | data[pos + 1]; if (pos + 2 + nal_size > size) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Buffer underrun in extra nal (%d >= %" G_GSIZE_FORMAT ")", pos + 2 + nal_size, size), (NULL)); return FALSE; } err = de265_push_NAL (dec->ctx, data + pos + 2, nal_size, 0, NULL); if (!de265_isOK (err)) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Failed to push data: %s (%d)", de265_get_error_text (err), err), (NULL)); return FALSE; } pos += 2 + nal_size; } } } GST_DEBUG ("Assuming packetized data (%d bytes length)", dec->length_size); } else { dec->format = GST_TYPE_LIBDE265_FORMAT_BYTESTREAM; GST_DEBUG_OBJECT (dec, "Assuming non-packetized data"); err = de265_push_data (dec->ctx, data, size, 0, NULL); if (!de265_isOK (err)) { gst_buffer_unmap (buf, &info); GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Failed to push codec data: %s (code=%d)", de265_get_error_text (err), err), (NULL)); return FALSE; } } gst_buffer_unmap (buf, &info); de265_push_end_of_NAL (dec->ctx); do { err = de265_decode (dec->ctx, &more); switch (err) { case DE265_OK: break; case DE265_ERROR_IMAGE_BUFFER_FULL: case DE265_ERROR_WAITING_FOR_INPUT_DATA: /* not really an error */ more = 0; break; default: if (!de265_isOK (err)) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Failed to decode codec data: %s (code=%d)", de265_get_error_text (err), err), (NULL)); return FALSE; } } } while (more); } else if ((value = gst_structure_get_value (str, "stream-format"))) { const gchar *str = g_value_get_string (value); if (strcmp (str, "byte-stream") == 0) { dec->format = GST_TYPE_LIBDE265_FORMAT_BYTESTREAM; GST_DEBUG_OBJECT (dec, "Assuming raw byte-stream"); } } } return TRUE; }
static GstFlowReturn gst_libde265_dec_parse_data (VIDEO_DECODER_BASE * parse, gboolean at_eos) #endif { GstLibde265Dec *dec = GST_LIBDE265_DEC (parse); const struct de265_image *img; de265_error ret = DE265_OK; int more = 0; #if GST_CHECK_VERSION(1,0,0) de265_PTS pts = (de265_PTS) frame->pts; #else de265_PTS pts = 0; #endif if (dec->buffer_full) { // return any pending images before decoding more data if ((img = de265_peek_next_picture(dec->ctx)) != NULL) { return _gst_libde265_image_available(parse, img); } dec->buffer_full = 0; } #if !GST_CHECK_VERSION(1,0,0) GstAdapter *adapter = parse->input_adapter; #endif gsize size = gst_adapter_available (adapter); if (size == 0) { return NEED_DATA_RESULT; } GstBuffer *buf = gst_adapter_take_buffer(adapter, size); uint8_t *frame_data; uint8_t *end_data; #if GST_CHECK_VERSION(1,0,0) GstMapInfo info; if (!gst_buffer_map(buf, &info, GST_MAP_READWRITE)) { return GST_FLOW_ERROR; } frame_data = info.data; #else frame_data = GST_BUFFER_DATA(buf); #endif end_data = frame_data + size; if (size > 0) { if (dec->mode == GST_TYPE_LIBDE265_DEC_PACKETIZED) { // replace 4-byte length fields with NAL start codes uint8_t *start_data = frame_data; while (start_data + 4 <= end_data) { int nal_size = READ_BE32(start_data); if (start_data + nal_size > end_data) { GST_ELEMENT_ERROR (parse, STREAM, DECODE, ("Overflow in input data, check data mode"), (NULL)); goto error; } ret = de265_push_NAL(dec->ctx, start_data + 4, nal_size, pts, NULL); if (ret != DE265_OK) { GST_ELEMENT_ERROR (parse, STREAM, DECODE, ("Error while pushing data: %s (code=%d)", de265_get_error_text(ret), ret), (NULL)); goto error; } start_data += 4 + nal_size; } } else { ret = de265_push_data(dec->ctx, frame_data, size, pts, NULL); } } else { ret = de265_flush_data(dec->ctx); } // decode as much as possible do { ret = de265_decode(dec->ctx, &more); } while (more && ret == DE265_OK); #if GST_CHECK_VERSION(1,0,0) gst_buffer_unmap(buf, &info); #endif gst_buffer_unref(buf); switch (ret) { case DE265_OK: break; case DE265_ERROR_IMAGE_BUFFER_FULL: dec->buffer_full = 1; if ((img = de265_peek_next_picture(dec->ctx)) == NULL) { return NEED_DATA_RESULT; } return _gst_libde265_image_available(parse, img);; case DE265_ERROR_WAITING_FOR_INPUT_DATA: return NEED_DATA_RESULT; default: GST_ELEMENT_ERROR (parse, STREAM, DECODE, ("Error while decoding: %s (code=%d)", de265_get_error_text(ret), ret), (NULL)); return GST_FLOW_ERROR; } while ((ret = de265_get_warning(dec->ctx)) != DE265_OK) { GST_ELEMENT_WARNING (parse, STREAM, DECODE, ("%s (code=%d)", de265_get_error_text(ret), ret), (NULL)); } if ((img = de265_peek_next_picture(dec->ctx)) == NULL) { // need more data return NEED_DATA_RESULT; } return _gst_libde265_image_available(parse, img); error: #if GST_CHECK_VERSION(1,0,0) gst_buffer_unmap(buf, &info); #endif gst_buffer_unref(buf); return GST_FLOW_ERROR; }