diff options
author | Joakim Plate <elupus@ecce.se> | 2013-06-26 22:07:28 +0200 |
---|---|---|
committer | Joakim Plate <elupus@ecce.se> | 2013-08-01 16:59:04 +0200 |
commit | 00189ad5d2ad590f952099078049a65db5ba9ff1 (patch) | |
tree | 7cc73d4dbd875ca9b879ad2e9173e5a4bcb69fcd /lib/ffmpeg/libavcodec | |
parent | ea8e821f93d99a5c20439782b7143b0d1f40ffc0 (diff) |
h264: expose h264 frame packing as stereo_mode metadata
Diffstat (limited to 'lib/ffmpeg/libavcodec')
-rw-r--r-- | lib/ffmpeg/libavcodec/h264.c | 3 | ||||
-rw-r--r-- | lib/ffmpeg/libavcodec/h264.h | 35 | ||||
-rw-r--r-- | lib/ffmpeg/libavcodec/h264_parser.c | 1 | ||||
-rw-r--r-- | lib/ffmpeg/libavcodec/h264_sei.c | 85 |
4 files changed, 123 insertions, 1 deletions
diff --git a/lib/ffmpeg/libavcodec/h264.c b/lib/ffmpeg/libavcodec/h264.c index 937ad7a3e2..85f2372e2e 100644 --- a/lib/ffmpeg/libavcodec/h264.c +++ b/lib/ffmpeg/libavcodec/h264.c @@ -1437,6 +1437,7 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx) h->prev_poc_msb = 1 << 16; h->prev_frame_num = -1; h->x264_build = -1; + h->sei_fpa.frame_packing_arrangement_cancel_flag = -1; ff_h264_reset_sei(h); if (avctx->codec_id == AV_CODEC_ID_H264) { if (avctx->ticks_per_frame == 1) { @@ -4783,6 +4784,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, out->f.reference &= ~DELAYED_PIC_REF; *got_frame = 1; *pict = out->f; + av_dict_set(&pict->metadata, "stereo_mode", ff_h264_sei_stereo_mode(h), 0); } return buf_index; @@ -4839,6 +4841,7 @@ not_extra: if (h->next_output_pic && (h->next_output_pic->sync || h->sync>1)) { *got_frame = 1; *pict = h->next_output_pic->f; + av_dict_set(&pict->metadata, "stereo_mode", ff_h264_sei_stereo_mode(h), 0); } } diff --git a/lib/ffmpeg/libavcodec/h264.h b/lib/ffmpeg/libavcodec/h264.h index 7ea613c6f3..15a0b212fb 100644 --- a/lib/ffmpeg/libavcodec/h264.h +++ b/lib/ffmpeg/libavcodec/h264.h @@ -126,7 +126,8 @@ typedef enum { SEI_TYPE_PIC_TIMING = 1, ///< picture timing SEI_TYPE_USER_DATA_ITU_T_T35 = 4, ///< user data registered by ITU-T Recommendation T.35 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; /** @@ -145,6 +146,19 @@ typedef enum { } SEI_PicStructType; /** + * frame_packing_arrangement types + */ +typedef enum { + SEI_FPA_TYPE_CHECKERBOARD = 0, + SEI_FPA_TYPE_INTERLEAVE_COLUMN = 1, + SEI_FPA_TYPE_INTERLEAVE_ROW = 2, + SEI_FPA_TYPE_SIDE_BY_SIDE = 3, + SEI_FPA_TYPE_TOP_BOTTOM = 4, + SEI_FPA_TYPE_INTERLEAVE_TEMPORAL = 5, + SEI_FPA_TYPE_2D = 6, +} SEI_FpaType; + +/** * Sequence parameter set */ typedef struct SPS { @@ -230,6 +244,17 @@ typedef struct PPS { } PPS; /** + * Frame Packing Arrangement Type + */ +typedef struct FPA { + int frame_packing_arrangement_id; + int frame_packing_arrangement_cancel_flag; ///< is previous arrangement canceled, -1 if never received + SEI_FpaType frame_packing_arrangement_type; + int content_interpretation_type; + int quincunx_sampling_flag; +} FPA; + +/** * Memory management control operation opcode. */ typedef enum MMCOOpcode { @@ -626,6 +651,8 @@ typedef struct H264Context { */ int valid_recovery_point; + FPA sei_fpa; + int luma_weight_flag[2]; ///< 7.4.3.2 luma_weight_lX_flag int chroma_weight_flag[2]; ///< 7.4.3.2 chroma_weight_lX_flag @@ -771,6 +798,12 @@ void ff_h264_filter_mb(H264Context *h, int mb_x, int mb_y, */ void ff_h264_reset_sei(H264Context *h); +/** + * Get stereo_mode string from the h264 frame_packing_arrangement + * @param h H.264 context. + */ +const char* ff_h264_sei_stereo_mode(H264Context *h); + /* * o-o o-o * / / / diff --git a/lib/ffmpeg/libavcodec/h264_parser.c b/lib/ffmpeg/libavcodec/h264_parser.c index 44b92b79e3..aff9ba17f0 100644 --- a/lib/ffmpeg/libavcodec/h264_parser.c +++ b/lib/ffmpeg/libavcodec/h264_parser.c @@ -158,6 +158,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, h->sei_dpb_output_delay = 0; h->sei_cpb_removal_delay = -1; h->sei_buffering_period_present = 0; + h->sei_fpa.frame_packing_arrangement_cancel_flag = -1; if (!buf_size) return 0; diff --git a/lib/ffmpeg/libavcodec/h264_sei.c b/lib/ffmpeg/libavcodec/h264_sei.c index ece54f1007..fc9b96f71e 100644 --- a/lib/ffmpeg/libavcodec/h264_sei.c +++ b/lib/ffmpeg/libavcodec/h264_sei.c @@ -194,6 +194,43 @@ static int decode_buffering_period(H264Context *h){ return 0; } +static int decode_frame_packing(H264Context *h, int size){ + int bits = get_bits_left(&h->gb); + + h->sei_fpa.frame_packing_arrangement_id = get_ue_golomb(&h->gb); + h->sei_fpa.frame_packing_arrangement_cancel_flag = get_bits(&h->gb, 1); + if (!h->sei_fpa.frame_packing_arrangement_cancel_flag) { + h->sei_fpa.frame_packing_arrangement_type = get_bits(&h->gb, 7); + h->sei_fpa.quincunx_sampling_flag = get_bits(&h->gb, 1); + h->sei_fpa.content_interpretation_type = get_bits(&h->gb, 6); + skip_bits(&h->gb, 1); /* spatial_flipping_flag */ + skip_bits(&h->gb, 1); /* frame0_flipped_flag */ + skip_bits(&h->gb, 1); /* field_views_flag */ + skip_bits(&h->gb, 1); /* current_frame_is_frame0_flag */ + skip_bits(&h->gb, 1); /* frame0_self_contained_flag */ + skip_bits(&h->gb, 1); /* frame1_self_contained_flag */ + if (!h->sei_fpa.quincunx_sampling_flag && h->sei_fpa.frame_packing_arrangement_type != 5) { + skip_bits(&h->gb, 4); /* frame0_grid_position_x */ + skip_bits(&h->gb, 4); /* frame0_grid_position_y */ + skip_bits(&h->gb, 4); /* frame1_grid_position_x */ + skip_bits(&h->gb, 4); /* frame1_grid_position_y */ + } + skip_bits(&h->gb, 8); /* frame_packing_arrangement_reserved_byte */ + get_ue_golomb(&h->gb) /* frame_packing_arrangement_repetition_period */; + } + skip_bits(&h->gb, 1); /* frame_packing_arrangement_extension_flag */ + + if (h->avctx->debug & FF_DEBUG_PICT_INFO) + av_log(h->avctx, AV_LOG_DEBUG, "SEI FPA %d %d %d %d %d\n", + h->sei_fpa.frame_packing_arrangement_id, + h->sei_fpa.frame_packing_arrangement_cancel_flag, + h->sei_fpa.frame_packing_arrangement_type, + h->sei_fpa.quincunx_sampling_flag, + h->sei_fpa.content_interpretation_type); + skip_bits(&h->gb, 8*size - (bits - get_bits_left(&h->gb))); + return 0; +} + int ff_h264_decode_sei(H264Context *h){ while (get_bits_left(&h->gb) > 16) { int size, type; @@ -236,6 +273,9 @@ int ff_h264_decode_sei(H264Context *h){ if(decode_buffering_period(h) < 0) return -1; break; + case SEI_TYPE_FRAME_PACKING: + if(decode_frame_packing(h, size) < 0) + return -1; default: skip_bits(&h->gb, 8*size); } @@ -246,3 +286,48 @@ int ff_h264_decode_sei(H264Context *h){ return 0; } + +const char* ff_h264_sei_stereo_mode(H264Context *h) +{ + if (h->sei_fpa.frame_packing_arrangement_cancel_flag == 0) { + switch (h->sei_fpa.frame_packing_arrangement_type) { + case SEI_FPA_TYPE_CHECKERBOARD: + if (h->sei_fpa.content_interpretation_type == 2) + return "checkerboard_rl"; + else + return "checkerboard_lr"; + case SEI_FPA_TYPE_INTERLEAVE_COLUMN: + if (h->sei_fpa.content_interpretation_type == 2) + return "col_interleaved_rl"; + else + return "col_interleaved_lr"; + case SEI_FPA_TYPE_INTERLEAVE_ROW: + if (h->sei_fpa.content_interpretation_type == 2) + return "row_interleaved_rl"; + else + return "row_interleaved_lr"; + case SEI_FPA_TYPE_SIDE_BY_SIDE: + if (h->sei_fpa.content_interpretation_type == 2) + return "right_left"; + else + return "left_right"; + case SEI_FPA_TYPE_TOP_BOTTOM: + if (h->sei_fpa.content_interpretation_type == 2) + return "bottom_top"; + else + return "top_bottom"; + case SEI_FPA_TYPE_INTERLEAVE_TEMPORAL: + if (h->sei_fpa.content_interpretation_type == 2) + return "block_rl"; + else + return "block_lr"; + case SEI_FPA_TYPE_2D: + default: + return "mono"; + } + } else if (h->sei_fpa.frame_packing_arrangement_cancel_flag == 1) { + return "mono"; + } else { + return NULL; + } +} |