mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-20 23:36:38 +00:00
theoradec: Use crop metadata if possible and refactor cropping code a bit
This commit is contained in:
parent
1483997207
commit
894875d705
2 changed files with 116 additions and 32 deletions
|
@ -102,6 +102,8 @@ static GstFlowReturn theora_dec_parse (GstVideoDecoder * decoder,
|
||||||
GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
|
GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos);
|
||||||
static GstFlowReturn theora_dec_handle_frame (GstVideoDecoder * decoder,
|
static GstFlowReturn theora_dec_handle_frame (GstVideoDecoder * decoder,
|
||||||
GstVideoCodecFrame * frame);
|
GstVideoCodecFrame * frame);
|
||||||
|
static gboolean theora_dec_configure_buffer_pool (GstVideoDecoder * decoder,
|
||||||
|
GstQuery * query, GstBufferPool * pool);
|
||||||
|
|
||||||
static GstFlowReturn theora_dec_decode_buffer (GstTheoraDec * dec,
|
static GstFlowReturn theora_dec_decode_buffer (GstTheoraDec * dec,
|
||||||
GstBuffer * buf, GstVideoCodecFrame * frame);
|
GstBuffer * buf, GstVideoCodecFrame * frame);
|
||||||
|
@ -183,6 +185,8 @@ gst_theora_dec_class_init (GstTheoraDecClass * klass)
|
||||||
video_decoder_class->parse = GST_DEBUG_FUNCPTR (theora_dec_parse);
|
video_decoder_class->parse = GST_DEBUG_FUNCPTR (theora_dec_parse);
|
||||||
video_decoder_class->handle_frame =
|
video_decoder_class->handle_frame =
|
||||||
GST_DEBUG_FUNCPTR (theora_dec_handle_frame);
|
GST_DEBUG_FUNCPTR (theora_dec_handle_frame);
|
||||||
|
video_decoder_class->configure_buffer_pool =
|
||||||
|
GST_DEBUG_FUNCPTR (theora_dec_configure_buffer_pool);
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
|
GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
|
||||||
}
|
}
|
||||||
|
@ -203,6 +207,7 @@ static void
|
||||||
gst_theora_dec_reset (GstTheoraDec * dec)
|
gst_theora_dec_reset (GstTheoraDec * dec)
|
||||||
{
|
{
|
||||||
dec->need_keyframe = TRUE;
|
dec->need_keyframe = TRUE;
|
||||||
|
dec->can_crop = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -424,16 +429,21 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
|
||||||
goto unsupported_format;
|
goto unsupported_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Use crop metadata */
|
GST_VIDEO_INFO_WIDTH (info) = dec->info.pic_width;
|
||||||
|
GST_VIDEO_INFO_HEIGHT (info) = dec->info.pic_height;
|
||||||
|
|
||||||
/* no cropping, use the encoded dimensions */
|
/* Ensure correct offsets in chroma for formats that need it
|
||||||
GST_VIDEO_INFO_WIDTH (info) = dec->info.frame_width;
|
* by rounding the offset. libtheora will add proper pixels,
|
||||||
GST_VIDEO_INFO_HEIGHT (info) = dec->info.frame_height;
|
* so no need to handle them ourselves. */
|
||||||
dec->offset_x = 0;
|
if (dec->info.pic_x & 1 && dec->info.pixel_fmt != TH_PF_444) {
|
||||||
dec->offset_y = 0;
|
GST_VIDEO_INFO_WIDTH (info)++;
|
||||||
|
}
|
||||||
|
if (dec->info.pic_y & 1 && dec->info.pixel_fmt == TH_PF_420) {
|
||||||
|
GST_VIDEO_INFO_HEIGHT (info)++;
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
|
GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
|
||||||
info->width, info->height, dec->offset_x, dec->offset_y);
|
info->width, info->height, dec->info.pic_x, dec->info.pic_y);
|
||||||
|
|
||||||
/* done */
|
/* done */
|
||||||
dec->decoder = th_decode_alloc (&dec->info, dec->setup);
|
dec->decoder = th_decode_alloc (&dec->info, dec->setup);
|
||||||
|
@ -548,13 +558,14 @@ theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
|
||||||
GstVideoCodecFrame * frame)
|
GstVideoCodecFrame * frame)
|
||||||
{
|
{
|
||||||
GstVideoDecoder *decoder = GST_VIDEO_DECODER (dec);
|
GstVideoDecoder *decoder = GST_VIDEO_DECODER (dec);
|
||||||
GstVideoInfo *info;
|
|
||||||
gint width, height, stride;
|
gint width, height, stride;
|
||||||
GstFlowReturn result;
|
GstFlowReturn result;
|
||||||
int i, plane;
|
gint i, comp;
|
||||||
guint8 *dest, *src;
|
guint8 *dest, *src;
|
||||||
GstBuffer *out;
|
GstVideoFrame vframe;
|
||||||
GstMapInfo minfo;
|
GstVideoCropMeta *crop;
|
||||||
|
gint pic_width, pic_height;
|
||||||
|
gint offset_x, offset_y;
|
||||||
|
|
||||||
result = gst_video_decoder_alloc_output_frame (decoder, frame);
|
result = gst_video_decoder_alloc_output_frame (decoder, frame);
|
||||||
|
|
||||||
|
@ -564,38 +575,77 @@ theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
out = frame->output_buffer;
|
if (!dec->can_crop) {
|
||||||
info = &dec->output_state->info;
|
/* we need to crop the hard way */
|
||||||
|
offset_x = dec->info.pic_x;
|
||||||
|
offset_y = dec->info.pic_y;
|
||||||
|
pic_width = dec->info.pic_width;
|
||||||
|
pic_height = dec->info.pic_height;
|
||||||
|
/* Ensure correct offsets in chroma for formats that need it
|
||||||
|
* by rounding the offset. libtheora will add proper pixels,
|
||||||
|
* so no need to handle them ourselves. */
|
||||||
|
if (offset_x & 1 && dec->info.pixel_fmt != TH_PF_444)
|
||||||
|
offset_x--;
|
||||||
|
if (offset_y & 1 && dec->info.pixel_fmt == TH_PF_420)
|
||||||
|
offset_y--;
|
||||||
|
} else {
|
||||||
|
/* copy the whole frame */
|
||||||
|
offset_x = 0;
|
||||||
|
offset_y = 0;
|
||||||
|
pic_width = dec->info.frame_width;
|
||||||
|
pic_height = dec->info.frame_height;
|
||||||
|
|
||||||
gst_buffer_map (out, &minfo, GST_MAP_WRITE);
|
if (dec->info.pic_width != dec->info.frame_width ||
|
||||||
|
dec->info.pic_height != dec->info.frame_height ||
|
||||||
|
dec->info.pic_x != 0 || dec->info.pic_y != 0) {
|
||||||
|
crop = gst_buffer_add_video_crop_meta (frame->output_buffer);
|
||||||
|
|
||||||
/* FIXME : Use crop metadata */
|
/* we can do things slightly more efficient when we know that
|
||||||
for (plane = 0; plane < 3; plane++) {
|
* downstream understands clipping */
|
||||||
width = GST_VIDEO_INFO_COMP_WIDTH (info, plane);
|
crop->x = dec->info.pic_x;
|
||||||
height = GST_VIDEO_INFO_COMP_HEIGHT (info, plane);
|
crop->y = dec->info.pic_y;
|
||||||
stride = GST_VIDEO_INFO_COMP_STRIDE (info, plane);
|
crop->width = dec->info.pic_width;
|
||||||
|
crop->height = dec->info.pic_height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dest = minfo.data + GST_VIDEO_INFO_COMP_OFFSET (info, plane);
|
/* if only libtheora would allow us to give it a destination frame */
|
||||||
src = buf[plane].data;
|
GST_CAT_TRACE_OBJECT (GST_CAT_PERFORMANCE, dec,
|
||||||
src +=
|
"doing unavoidable video frame copy");
|
||||||
((height ==
|
|
||||||
GST_VIDEO_INFO_HEIGHT (info)) ? dec->offset_y : dec->offset_y / 2)
|
if (G_UNLIKELY (!gst_video_frame_map (&vframe, &dec->output_state->info,
|
||||||
* buf[plane].stride;
|
frame->output_buffer, GST_MAP_WRITE)))
|
||||||
src +=
|
goto invalid_frame;
|
||||||
(width ==
|
|
||||||
GST_VIDEO_INFO_WIDTH (info)) ? dec->offset_x : dec->offset_x / 2;
|
for (comp = 0; comp < 3; comp++) {
|
||||||
|
width =
|
||||||
|
GST_VIDEO_FORMAT_INFO_SCALE_WIDTH (vframe.info.finfo, comp, pic_width);
|
||||||
|
height =
|
||||||
|
GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (vframe.info.finfo, comp,
|
||||||
|
pic_height);
|
||||||
|
stride = GST_VIDEO_FRAME_COMP_STRIDE (&vframe, comp);
|
||||||
|
dest = GST_VIDEO_FRAME_COMP_DATA (&vframe, comp);
|
||||||
|
|
||||||
|
src = buf[comp].data;
|
||||||
|
src += ((height == pic_height) ? offset_y : offset_y / 2)
|
||||||
|
* buf[comp].stride;
|
||||||
|
src += (width == pic_width) ? offset_x : offset_x / 2;
|
||||||
|
|
||||||
for (i = 0; i < height; i++) {
|
for (i = 0; i < height; i++) {
|
||||||
memcpy (dest, src, width);
|
memcpy (dest, src, width);
|
||||||
|
|
||||||
dest += stride;
|
dest += stride;
|
||||||
src += buf[plane].stride;
|
src += buf[comp].stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gst_video_frame_unmap (&vframe);
|
||||||
gst_buffer_unmap (out, &minfo);
|
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
invalid_frame:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (dec, "could not map video frame");
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
|
@ -744,6 +794,39 @@ theora_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
theora_dec_configure_buffer_pool (GstVideoDecoder * decoder, GstQuery * query,
|
||||||
|
GstBufferPool * pool)
|
||||||
|
{
|
||||||
|
GstTheoraDec *dec = GST_THEORA_DEC (decoder);
|
||||||
|
|
||||||
|
dec->can_crop =
|
||||||
|
gst_query_has_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE);
|
||||||
|
if (dec->can_crop) {
|
||||||
|
GstStructure *config;
|
||||||
|
GstVideoInfo info;
|
||||||
|
GstCaps *caps;
|
||||||
|
guint size, min, max;
|
||||||
|
|
||||||
|
config = gst_buffer_pool_get_config (pool);
|
||||||
|
gst_buffer_pool_config_get_params (config, &caps, &size, &min, &max);
|
||||||
|
|
||||||
|
/* Calculate uncropped size */
|
||||||
|
gst_video_info_init (&info);
|
||||||
|
gst_video_info_from_caps (&info, caps);
|
||||||
|
gst_video_info_set_format (&info, info.finfo->format, dec->info.frame_width,
|
||||||
|
dec->info.frame_height);
|
||||||
|
size = MAX (size, info.size);
|
||||||
|
|
||||||
|
gst_buffer_pool_config_set_params (config, caps, size, min, max);
|
||||||
|
|
||||||
|
gst_buffer_pool_set_config (pool, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GST_VIDEO_DECODER_CLASS (parent_class)->configure_buffer_pool (decoder,
|
||||||
|
query, pool);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
theora_dec_set_property (GObject * object, guint prop_id,
|
theora_dec_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
const GValue * value, GParamSpec * pspec)
|
||||||
|
|
|
@ -69,7 +69,6 @@ struct _GstTheoraDec
|
||||||
gboolean need_keyframe;
|
gboolean need_keyframe;
|
||||||
GstVideoCodecState *input_state;
|
GstVideoCodecState *input_state;
|
||||||
GstVideoCodecState *output_state;
|
GstVideoCodecState *output_state;
|
||||||
gint offset_x, offset_y;
|
|
||||||
|
|
||||||
/* telemetry debuging options */
|
/* telemetry debuging options */
|
||||||
gint telemetry_mv;
|
gint telemetry_mv;
|
||||||
|
@ -78,6 +77,8 @@ struct _GstTheoraDec
|
||||||
gint telemetry_bits;
|
gint telemetry_bits;
|
||||||
|
|
||||||
GstTagList *tags;
|
GstTagList *tags;
|
||||||
|
|
||||||
|
gboolean can_crop;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstTheoraDecClass
|
struct _GstTheoraDecClass
|
||||||
|
|
Loading…
Reference in a new issue