mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-18 22:36:33 +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);
|
||||
static GstFlowReturn theora_dec_handle_frame (GstVideoDecoder * decoder,
|
||||
GstVideoCodecFrame * frame);
|
||||
static gboolean theora_dec_configure_buffer_pool (GstVideoDecoder * decoder,
|
||||
GstQuery * query, GstBufferPool * pool);
|
||||
|
||||
static GstFlowReturn theora_dec_decode_buffer (GstTheoraDec * dec,
|
||||
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->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");
|
||||
}
|
||||
|
@ -203,6 +207,7 @@ static void
|
|||
gst_theora_dec_reset (GstTheoraDec * dec)
|
||||
{
|
||||
dec->need_keyframe = TRUE;
|
||||
dec->can_crop = FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -424,16 +429,21 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
|
|||
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 */
|
||||
GST_VIDEO_INFO_WIDTH (info) = dec->info.frame_width;
|
||||
GST_VIDEO_INFO_HEIGHT (info) = dec->info.frame_height;
|
||||
dec->offset_x = 0;
|
||||
dec->offset_y = 0;
|
||||
/* 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 (dec->info.pic_x & 1 && dec->info.pixel_fmt != TH_PF_444) {
|
||||
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",
|
||||
info->width, info->height, dec->offset_x, dec->offset_y);
|
||||
info->width, info->height, dec->info.pic_x, dec->info.pic_y);
|
||||
|
||||
/* done */
|
||||
dec->decoder = th_decode_alloc (&dec->info, dec->setup);
|
||||
|
@ -548,13 +558,14 @@ theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
|
|||
GstVideoCodecFrame * frame)
|
||||
{
|
||||
GstVideoDecoder *decoder = GST_VIDEO_DECODER (dec);
|
||||
GstVideoInfo *info;
|
||||
gint width, height, stride;
|
||||
GstFlowReturn result;
|
||||
int i, plane;
|
||||
gint i, comp;
|
||||
guint8 *dest, *src;
|
||||
GstBuffer *out;
|
||||
GstMapInfo minfo;
|
||||
GstVideoFrame vframe;
|
||||
GstVideoCropMeta *crop;
|
||||
gint pic_width, pic_height;
|
||||
gint offset_x, offset_y;
|
||||
|
||||
result = gst_video_decoder_alloc_output_frame (decoder, frame);
|
||||
|
||||
|
@ -564,38 +575,77 @@ theora_handle_image (GstTheoraDec * dec, th_ycbcr_buffer buf,
|
|||
return result;
|
||||
}
|
||||
|
||||
out = frame->output_buffer;
|
||||
info = &dec->output_state->info;
|
||||
if (!dec->can_crop) {
|
||||
/* 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 */
|
||||
for (plane = 0; plane < 3; plane++) {
|
||||
width = GST_VIDEO_INFO_COMP_WIDTH (info, plane);
|
||||
height = GST_VIDEO_INFO_COMP_HEIGHT (info, plane);
|
||||
stride = GST_VIDEO_INFO_COMP_STRIDE (info, plane);
|
||||
/* we can do things slightly more efficient when we know that
|
||||
* downstream understands clipping */
|
||||
crop->x = dec->info.pic_x;
|
||||
crop->y = dec->info.pic_y;
|
||||
crop->width = dec->info.pic_width;
|
||||
crop->height = dec->info.pic_height;
|
||||
}
|
||||
}
|
||||
|
||||
dest = minfo.data + GST_VIDEO_INFO_COMP_OFFSET (info, plane);
|
||||
src = buf[plane].data;
|
||||
src +=
|
||||
((height ==
|
||||
GST_VIDEO_INFO_HEIGHT (info)) ? dec->offset_y : dec->offset_y / 2)
|
||||
* buf[plane].stride;
|
||||
src +=
|
||||
(width ==
|
||||
GST_VIDEO_INFO_WIDTH (info)) ? dec->offset_x : dec->offset_x / 2;
|
||||
/* if only libtheora would allow us to give it a destination frame */
|
||||
GST_CAT_TRACE_OBJECT (GST_CAT_PERFORMANCE, dec,
|
||||
"doing unavoidable video frame copy");
|
||||
|
||||
if (G_UNLIKELY (!gst_video_frame_map (&vframe, &dec->output_state->info,
|
||||
frame->output_buffer, GST_MAP_WRITE)))
|
||||
goto invalid_frame;
|
||||
|
||||
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++) {
|
||||
memcpy (dest, src, width);
|
||||
|
||||
dest += stride;
|
||||
src += buf[plane].stride;
|
||||
src += buf[comp].stride;
|
||||
}
|
||||
}
|
||||
|
||||
gst_buffer_unmap (out, &minfo);
|
||||
gst_video_frame_unmap (&vframe);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
invalid_frame:
|
||||
{
|
||||
GST_DEBUG_OBJECT (dec, "could not map video frame");
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
|
@ -744,6 +794,39 @@ theora_dec_handle_frame (GstVideoDecoder * bdec, GstVideoCodecFrame * frame)
|
|||
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
|
||||
theora_dec_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
|
|
|
@ -69,7 +69,6 @@ struct _GstTheoraDec
|
|||
gboolean need_keyframe;
|
||||
GstVideoCodecState *input_state;
|
||||
GstVideoCodecState *output_state;
|
||||
gint offset_x, offset_y;
|
||||
|
||||
/* telemetry debuging options */
|
||||
gint telemetry_mv;
|
||||
|
@ -78,6 +77,8 @@ struct _GstTheoraDec
|
|||
gint telemetry_bits;
|
||||
|
||||
GstTagList *tags;
|
||||
|
||||
gboolean can_crop;
|
||||
};
|
||||
|
||||
struct _GstTheoraDecClass
|
||||
|
|
Loading…
Reference in a new issue