This matches the matroska defintion of stereo_mode, with no metadata written if no info exist in sei Signed-off-by: Michael Niedermayer <michaelni@gmx.at>tags/n2.1
| @@ -1512,6 +1512,7 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx) | |||||
| h->prev_poc_msb = 1 << 16; | h->prev_poc_msb = 1 << 16; | ||||
| h->prev_frame_num = -1; | h->prev_frame_num = -1; | ||||
| h->x264_build = -1; | h->x264_build = -1; | ||||
| h->sei_fpa.frame_packing_arrangement_cancel_flag = -1; | |||||
| ff_h264_reset_sei(h); | ff_h264_reset_sei(h); | ||||
| if (avctx->codec_id == AV_CODEC_ID_H264) { | if (avctx->codec_id == AV_CODEC_ID_H264) { | ||||
| if (avctx->ticks_per_frame == 1) { | if (avctx->ticks_per_frame == 1) { | ||||
| @@ -4859,6 +4860,8 @@ static int output_frame(H264Context *h, AVFrame *dst, Picture *srcp) | |||||
| if (ret < 0) | if (ret < 0) | ||||
| return ret; | return ret; | ||||
| av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(h), 0); | |||||
| if (!srcp->crop) | if (!srcp->crop) | ||||
| return 0; | return 0; | ||||
| @@ -127,7 +127,8 @@ typedef enum { | |||||
| SEI_TYPE_PIC_TIMING = 1, ///< picture timing | 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_ITU_T_T35 = 4, ///< user data registered by ITU-T Recommendation T.35 | ||||
| SEI_TYPE_USER_DATA_UNREGISTERED = 5, ///< unregistered user data | 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; | } SEI_Type; | ||||
| /** | /** | ||||
| @@ -145,6 +146,19 @@ typedef enum { | |||||
| SEI_PIC_STRUCT_FRAME_TRIPLING = 8 ///< 8: %frame tripling | SEI_PIC_STRUCT_FRAME_TRIPLING = 8 ///< 8: %frame tripling | ||||
| } SEI_PicStructType; | } 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 | * Sequence parameter set | ||||
| */ | */ | ||||
| @@ -232,6 +246,18 @@ typedef struct PPS { | |||||
| int chroma_qp_diff; | int chroma_qp_diff; | ||||
| } 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 frame_packing_arrangement_repetition_period; | |||||
| int content_interpretation_type; | |||||
| int quincunx_sampling_flag; | |||||
| } FPA; | |||||
| /** | /** | ||||
| * Memory management control operation opcode. | * Memory management control operation opcode. | ||||
| */ | */ | ||||
| @@ -628,6 +654,8 @@ typedef struct H264Context { | |||||
| */ | */ | ||||
| int valid_recovery_point; | int valid_recovery_point; | ||||
| FPA sei_fpa; | |||||
| int luma_weight_flag[2]; ///< 7.4.3.2 luma_weight_lX_flag | 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 | int chroma_weight_flag[2]; ///< 7.4.3.2 chroma_weight_lX_flag | ||||
| @@ -775,6 +803,12 @@ void ff_h264_filter_mb(H264Context *h, int mb_x, int mb_y, | |||||
| */ | */ | ||||
| void ff_h264_reset_sei(H264Context *h); | 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 | * o-o o-o | ||||
| * / / / | * / / / | ||||
| @@ -172,6 +172,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, | |||||
| h->sei_dpb_output_delay = 0; | h->sei_dpb_output_delay = 0; | ||||
| h->sei_cpb_removal_delay = -1; | h->sei_cpb_removal_delay = -1; | ||||
| h->sei_buffering_period_present = 0; | h->sei_buffering_period_present = 0; | ||||
| h->sei_fpa.frame_packing_arrangement_cancel_flag = -1; | |||||
| if (!buf_size) | if (!buf_size) | ||||
| return 0; | return 0; | ||||
| @@ -204,6 +204,44 @@ static int decode_buffering_period(H264Context *h){ | |||||
| return 0; | 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 */ | |||||
| h->sei_fpa.frame_packing_arrangement_repetition_period = 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 %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, | |||||
| h->sei_fpa.frame_packing_arrangement_repetition_period); | |||||
| skip_bits_long(&h->gb, 8*size - (bits - get_bits_left(&h->gb))); | |||||
| return 0; | |||||
| } | |||||
| int ff_h264_decode_sei(H264Context *h){ | int ff_h264_decode_sei(H264Context *h){ | ||||
| while (get_bits_left(&h->gb) > 16) { | while (get_bits_left(&h->gb) > 16) { | ||||
| int size, type; | int size, type; | ||||
| @@ -246,6 +284,9 @@ int ff_h264_decode_sei(H264Context *h){ | |||||
| if(decode_buffering_period(h) < 0) | if(decode_buffering_period(h) < 0) | ||||
| return -1; | return -1; | ||||
| break; | break; | ||||
| case SEI_TYPE_FRAME_PACKING: | |||||
| if(decode_frame_packing(h, size) < 0) | |||||
| return -1; | |||||
| default: | default: | ||||
| skip_bits(&h->gb, 8*size); | skip_bits(&h->gb, 8*size); | ||||
| } | } | ||||
| @@ -256,3 +297,48 @@ int ff_h264_decode_sei(H264Context *h){ | |||||
| return 0; | 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; | |||||
| } | |||||
| } | |||||