static int gst_libde265_dec_get_buffer (de265_decoder_context * ctx, struct de265_image_spec *spec, struct de265_image *img, void *userdata) { GstVideoDecoder *base = (GstVideoDecoder *) userdata; GstLibde265Dec *dec = GST_LIBDE265_DEC (base); GstVideoCodecFrame *frame = NULL; int i; int width = spec->width; int height = spec->height; GstFlowReturn ret; struct GstLibde265FrameRef *ref; GstVideoInfo *info; int frame_number; frame_number = (uintptr_t) de265_get_image_user_data (img) - 1; if (G_UNLIKELY (frame_number == -1)) { /* should not happen... */ GST_WARNING_OBJECT (base, "Frame has no number assigned!"); goto fallback; } frame = gst_video_decoder_get_frame (base, frame_number); if (G_UNLIKELY (frame == NULL)) { /* should not happen... */ GST_WARNING_OBJECT (base, "Couldn't get codec frame!"); goto fallback; } if (width % spec->alignment) { width += spec->alignment - (width % spec->alignment); } if (width != spec->visible_width || height != spec->visible_height) { /* clipping not supported for now */ goto fallback; } ret = _gst_libde265_image_available (base, width, height); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_ERROR_OBJECT (dec, "Failed to notify about available image"); goto fallback; } ret = gst_video_decoder_allocate_output_frame (GST_VIDEO_DECODER (dec), frame); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_ERROR_OBJECT (dec, "Failed to allocate output buffer"); goto fallback; } ref = (struct GstLibde265FrameRef *) g_malloc0 (sizeof (*ref)); g_assert (ref != NULL); ref->decoder = base; ref->frame = frame; gst_buffer_replace (&ref->buffer, frame->output_buffer); gst_buffer_replace (&frame->output_buffer, NULL); info = &dec->output_state->info; if (!gst_video_frame_map (&ref->vframe, info, ref->buffer, GST_MAP_READWRITE)) { GST_ERROR_OBJECT (dec, "Failed to map frame output buffer"); goto error; } ref->mapped = TRUE; if (GST_VIDEO_FRAME_PLANE_STRIDE (&ref->vframe, 0) < width * GST_VIDEO_FRAME_COMP_PSTRIDE (&ref->vframe, 0)) { GST_DEBUG_OBJECT (dec, "plane 0: pitch too small (%d/%d*%d)", GST_VIDEO_FRAME_PLANE_STRIDE (&ref->vframe, 0), width, GST_VIDEO_FRAME_COMP_PSTRIDE (&ref->vframe, 0)); goto error; } if (GST_VIDEO_FRAME_COMP_HEIGHT (&ref->vframe, 0) < height) { GST_DEBUG_OBJECT (dec, "plane 0: lines too few (%d/%d)", GST_VIDEO_FRAME_COMP_HEIGHT (&ref->vframe, 0), height); goto error; } for (i = 0; i < 3; i++) { uint8_t *data; int stride = GST_VIDEO_FRAME_PLANE_STRIDE (&ref->vframe, i); if (stride % spec->alignment) { GST_DEBUG_OBJECT (dec, "plane %d: pitch not aligned (%d%%%d)", i, stride, spec->alignment); goto error; } data = GST_VIDEO_FRAME_PLANE_DATA (&ref->vframe, i); if ((uintptr_t) (data) % spec->alignment) { GST_DEBUG_OBJECT (dec, "plane %d not aligned", i); goto error; } de265_set_image_plane (img, i, data, stride, ref); } return 1; error: gst_libde265_dec_release_frame_ref (ref); frame = NULL; fallback: if (frame != NULL) { gst_video_codec_frame_unref (frame); } return de265_get_default_image_allocation_functions ()->get_buffer (ctx, spec, img, userdata); }
static GstFlowReturn _gst_libde265_return_image (GstVideoDecoder * decoder, GstVideoCodecFrame * frame, const struct de265_image *img) { GstLibde265Dec *dec = GST_LIBDE265_DEC (decoder); struct GstLibde265FrameRef *ref; GstFlowReturn result; GstVideoFrame outframe; GstVideoCodecFrame *out_frame; int frame_number; int plane; ref = (struct GstLibde265FrameRef *) de265_get_image_plane_user_data (img, 0); if (ref != NULL) { /* decoder is using direct rendering */ out_frame = gst_video_codec_frame_ref (ref->frame); if (frame != NULL) { gst_video_codec_frame_unref (frame); } gst_buffer_replace (&out_frame->output_buffer, ref->buffer); gst_buffer_replace (&ref->buffer, NULL); return gst_video_decoder_finish_frame (decoder, out_frame); } result = _gst_libde265_image_available (decoder, de265_get_image_width (img, 0), de265_get_image_height (img, 0)); if (result != GST_FLOW_OK) { GST_ERROR_OBJECT (dec, "Failed to notify about available image"); return result; } frame_number = (uintptr_t) de265_get_image_user_data (img) - 1; if (frame_number != -1) { out_frame = gst_video_decoder_get_frame (decoder, frame_number); } else { out_frame = NULL; } if (frame != NULL) { gst_video_codec_frame_unref (frame); } if (out_frame == NULL) { GST_ERROR_OBJECT (dec, "No frame available to return"); return GST_FLOW_ERROR; } result = gst_video_decoder_allocate_output_frame (decoder, out_frame); if (result != GST_FLOW_OK) { GST_ERROR_OBJECT (dec, "Failed to allocate output frame"); return result; } g_assert (dec->output_state != NULL); if (!gst_video_frame_map (&outframe, &dec->output_state->info, out_frame->output_buffer, GST_MAP_WRITE)) { GST_ERROR_OBJECT (dec, "Failed to map output buffer"); return GST_FLOW_ERROR; } for (plane = 0; plane < 3; plane++) { int width = de265_get_image_width (img, plane); int height = de265_get_image_height (img, plane); int srcstride = width; int dststride = GST_VIDEO_FRAME_COMP_STRIDE (&outframe, plane); const uint8_t *src = de265_get_image_plane (img, plane, &srcstride); uint8_t *dest = GST_VIDEO_FRAME_COMP_DATA (&outframe, plane); if (srcstride == width && dststride == width) { memcpy (dest, src, height * width); } else { while (height--) { memcpy (dest, src, width); src += srcstride; dest += dststride; } } } gst_video_frame_unmap (&outframe); return gst_video_decoder_finish_frame (decoder, out_frame); }
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; }