Browse Source

h264: add frame packing as stereo_mode frame metadata

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
Joakim Plate Michael Niedermayer 12 years ago
parent
commit
8710a634a5
4 changed files with 125 additions and 1 deletions
  1. +3
    -0
      libavcodec/h264.c
  2. +35
    -1
      libavcodec/h264.h
  3. +1
    -0
      libavcodec/h264_parser.c
  4. +86
    -0
      libavcodec/h264_sei.c

+ 3
- 0
libavcodec/h264.c View File

@@ -1512,6 +1512,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) {
@@ -4859,6 +4860,8 @@ static int output_frame(H264Context *h, AVFrame *dst, Picture *srcp)
if (ret < 0)
return ret;

av_dict_set(&dst->metadata, "stereo_mode", ff_h264_sei_stereo_mode(h), 0);

if (!srcp->crop)
return 0;



+ 35
- 1
libavcodec/h264.h View File

@@ -127,7 +127,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_PIC_STRUCT_FRAME_TRIPLING = 8 ///< 8: %frame tripling
} 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
*/
@@ -232,6 +246,18 @@ typedef struct PPS {
int chroma_qp_diff;
} 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.
*/
@@ -628,6 +654,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

@@ -775,6 +803,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
* / / /


+ 1
- 0
libavcodec/h264_parser.c View File

@@ -172,6 +172,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;


+ 86
- 0
libavcodec/h264_sei.c View File

@@ -204,6 +204,44 @@ 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 */
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){
while (get_bits_left(&h->gb) > 16) {
int size, type;
@@ -246,6 +284,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);
}
@@ -256,3 +297,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;
}
}

Loading…
Cancel
Save