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 GstFlowReturn gst_libde265_dec_finish (GstVideoDecoder * decoder) { GstLibde265Dec *dec = GST_LIBDE265_DEC (decoder); de265_error err; const struct de265_image *img; int more; GstFlowReturn result; err = de265_flush_data (dec->ctx); if (!de265_isOK (err)) { GST_ELEMENT_ERROR (decoder, STREAM, DECODE, ("Failed to flush decoder: %s (code=%d)", de265_get_error_text (err), err), (NULL)); return GST_FLOW_ERROR; } do { err = de265_decode (dec->ctx, &more); switch (err) { case DE265_OK: case DE265_ERROR_IMAGE_BUFFER_FULL: img = de265_get_next_picture (dec->ctx); if (img != NULL) { result = _gst_libde265_return_image (decoder, NULL, img); if (result != GST_FLOW_OK) { return result; } } break; 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 GST_FLOW_OK; }
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; }
static int ff_libde265dec_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { DE265Context *ctx = (DE265Context *) avctx->priv_data; AVFrame *picture = (AVFrame *) data; const struct de265_image *img; de265_error err; int ret; int64_t pts; #if LIBDE265_NUMERIC_VERSION >= 0x00050000 int more = 0; #endif const uint8_t* src[4]; int stride[4]; if (avpkt->size > 0) { if (avpkt->pts != AV_NOPTS_VALUE) { pts = avpkt->pts; } else { pts = avctx->reordered_opaque; } // replace 4-byte length fields with NAL start codes uint8_t* avpkt_data = avpkt->data; uint8_t* avpkt_end = avpkt->data + avpkt->size; while (avpkt_data + 4 <= avpkt_end) { int nal_size = AV_RB32(avpkt_data); #if LIBDE265_NUMERIC_VERSION < 0x00050000 AV_WB32(avpkt_data, 0x00000001); #else err = de265_push_NAL(ctx->decoder, avpkt_data + 4, nal_size, pts, NULL); if (err != DE265_OK) { const char *error = de265_get_error_text(err); av_log(avctx, AV_LOG_ERROR, "Failed to push data: %s\n", error); return AVERROR_INVALIDDATA; } #endif avpkt_data += 4 + nal_size; } #if LIBDE265_NUMERIC_VERSION >= 0x00050000 } else { de265_flush_data(ctx->decoder); #endif } #if LIBDE265_NUMERIC_VERSION < 0x00050000 // insert input packet PTS into sorted queue if (ctx->pts_queue_len < DE265_MAX_PTS_QUEUE) { int pos=0; while (ctx->pts_queue[pos] < pts && pos<ctx->pts_queue_len) { pos++; } if (pos < ctx->pts_queue_len) { memmove(&ctx->pts_queue[pos+1], &ctx->pts_queue[pos], sizeof(int64_t) * (ctx->pts_queue_len - pos)); } ctx->pts_queue[pos] = pts; ctx->pts_queue_len++; if (ctx->pts_queue_len > ctx->pts_min_queue_len) { ctx->pts_min_queue_len = ctx->pts_queue_len; } } err = de265_decode_data(ctx->decoder, avpkt->data, avpkt->size); #else // decode as much as possible do { err = de265_decode(ctx->decoder, &more); } while (more && err == DE265_OK); #endif switch (err) { case DE265_OK: case DE265_ERROR_IMAGE_BUFFER_FULL: #if LIBDE265_NUMERIC_VERSION >= 0x00050000 case DE265_ERROR_WAITING_FOR_INPUT_DATA: #endif break; default: { const char *error = de265_get_error_text(err); av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error); return AVERROR_INVALIDDATA; } } if ((img = de265_get_next_picture(ctx->decoder)) != NULL) { int width; int height; if (de265_get_chroma_format(img) != de265_chroma_420) { av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d)\n", de265_get_chroma_format(img)); return AVERROR_INVALIDDATA; } width = de265_get_image_width(img,0); height = de265_get_image_height(img,0); if (width != avctx->width || height != avctx->height) { if (avctx->width != 0) av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n", avctx->width, avctx->height, width, height); if (av_image_check_size(width, height, 0, avctx)) { return AVERROR_INVALIDDATA; } avcodec_set_dimensions(avctx, width, height); } #if LIBDE265_NUMERIC_VERSION < 0x00050000 if (ctx->pts_queue_len < ctx->pts_min_queue_len) { // fill pts queue to ensure reordering works return avpkt->size; } #endif picture->width = avctx->width; picture->height = avctx->height; picture->format = avctx->pix_fmt; if ((ret = av_frame_get_buffer(picture, 32)) < 0) { return ret; } for (int i=0;i<4;i++) { src[i] = de265_get_image_plane(img,i, &stride[i]); } av_image_copy(picture->data, picture->linesize, src, stride, avctx->pix_fmt, width, height); *got_frame = 1; #if LIBDE265_NUMERIC_VERSION < 0x00050000 // assign next PTS from queue if (ctx->pts_queue_len > 0) { picture->reordered_opaque = ctx->pts_queue[0]; picture->pkt_pts = ctx->pts_queue[0]; if (ctx->pts_queue_len>1) { memmove(&ctx->pts_queue[0], &ctx->pts_queue[1], sizeof(int64_t) * (ctx->pts_queue_len-1)); } ctx->pts_queue_len--; } #else picture->reordered_opaque = de265_get_image_PTS(img); picture->pkt_pts = de265_get_image_PTS(img); #endif } return avpkt->size; }