From 5b10ef729f610fcbc9c485e7b643ce53268144cb Mon Sep 17 00:00:00 2001 From: Vittorio Giovara Date: Wed, 20 Feb 2013 16:34:58 +0100 Subject: h264: parse frame packing arrangement SEI messages and save relevant stereo3d information --- libavcodec/h264.c | 41 +++++++++++++++++++++++++++++++++++++++++ libavcodec/h264.h | 11 ++++++++++- libavcodec/h264_sei.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 86d453bba7..29a69608ec 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -27,6 +27,7 @@ #include "libavutil/avassert.h" #include "libavutil/imgutils.h" +#include "libavutil/stereo3d.h" #include "internal.h" #include "cabac.h" #include "cabac_functions.h" @@ -2029,6 +2030,46 @@ static void decode_postinit(H264Context *h, int setup_finished) } } + if (h->sei_frame_packing_present && + h->frame_packing_arrangement_type >= 0 && + h->frame_packing_arrangement_type <= 6 && + h->content_interpretation_type > 0 && + h->content_interpretation_type < 3) { + AVStereo3D *stereo = av_stereo3d_create_side_data(&cur->f); + if (!stereo) + return; + + switch (h->frame_packing_arrangement_type) { + case 0: + stereo->type = AV_STEREO3D_CHECKERBOARD; + break; + case 1: + stereo->type = AV_STEREO3D_LINES; + break; + case 2: + stereo->type = AV_STEREO3D_COLUMNS; + break; + case 3: + if (h->quincunx_subsampling) + stereo->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX; + else + stereo->type = AV_STEREO3D_SIDEBYSIDE; + break; + case 4: + stereo->type = AV_STEREO3D_TOPBOTTOM; + break; + case 5: + stereo->type = AV_STEREO3D_FRAMESEQUENCE; + break; + case 6: + stereo->type = AV_STEREO3D_2D; + break; + } + + if (h->content_interpretation_type == 2) + stereo->flags = AV_STEREO3D_FLAG_INVERT; + } + // FIXME do something with unavailable reference frames /* Sort B-frames into display order */ diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 920e3fc1c8..a828bf9e57 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -123,7 +123,8 @@ typedef enum { SEI_BUFFERING_PERIOD = 0, ///< buffering period (H.264, D.1.1) SEI_TYPE_PIC_TIMING = 1, ///< picture timing SEI_TYPE_USER_DATA_UNREGISTERED = 5, ///< unregistered user data - SEI_TYPE_RECOVERY_POINT = 6 ///< recovery point (frame # to decoder sync) + SEI_TYPE_RECOVERY_POINT = 6, ///< recovery point (frame # to decoder sync) + SEI_TYPE_FRAME_PACKING = 45, ///< frame packing arrangement } SEI_Type; /** @@ -585,6 +586,14 @@ typedef struct H264Context { */ int prev_interlaced_frame; + /** + * frame_packing_arrangment SEI message + */ + int sei_frame_packing_present; + int frame_packing_arrangement_type; + int content_interpretation_type; + int quincunx_subsampling; + /** * Bit set of clock types for fields/frames in picture timing SEI message. * For each found ct_type, appropriate bit is set (e.g., bit 1 for diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 27a2c7689c..746c2132c1 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -42,6 +42,7 @@ void ff_h264_reset_sei(H264Context *h) h->sei_dpb_output_delay = 0; h->sei_cpb_removal_delay = -1; h->sei_buffering_period_present = 0; + h->sei_frame_packing_present = 0; } static int decode_picture_timing(H264Context *h) @@ -175,6 +176,40 @@ static int decode_buffering_period(H264Context *h) return 0; } +static int decode_frame_packing_arrangement(H264Context *h) +{ + int cancel; + int quincunx = 0; + int content = -1; + int type = -1; + + get_ue_golomb(&h->gb); // frame_packing_arrangement_id + cancel = get_bits1(&h->gb); // frame_packing_arrangement_cancel_flag + if (cancel == 0) { + type = get_bits(&h->gb, 7); // frame_packing_arrangement_type + quincunx = get_bits1(&h->gb); // quincunx_sampling_flag + content = get_bits(&h->gb, 6); // content_interpretation_type + + // the following skips: spatial_flipping_flag, frame0_flipped_flag, + // field_views_flag, current_frame_is_frame0_flag, + // frame0_self_contained_flag, frame1_self_contained_flag + skip_bits(&h->gb, 6); + + if (quincunx == 0 && type != 5) + skip_bits(&h->gb, 16); // frame[01]_grid_position_[xy] + skip_bits(&h->gb, 8); // frame_packing_arrangement_reserved_byte + get_ue_golomb(&h->gb); // frame_packing_arrangement_repetition_period + } + skip_bits1(&h->gb); // frame_packing_arrangement_extension_flag + + h->sei_frame_packing_present = (cancel == 0); + h->frame_packing_arrangement_type = type; + h->content_interpretation_type = content; + h->quincunx_subsampling = quincunx; + + return 0; +} + int ff_h264_decode_sei(H264Context *h) { while (get_bits_left(&h->gb) > 16) { @@ -217,6 +252,11 @@ int ff_h264_decode_sei(H264Context *h) if (ret < 0) return ret; break; + case SEI_TYPE_FRAME_PACKING: + ret = decode_frame_packing_arrangement(h); + if (ret < 0) + return ret; + break; default: av_log(h->avctx, AV_LOG_DEBUG, "unknown SEI type %d\n", type); skip_bits(&h->gb, 8 * size); -- cgit v1.2.3