[FFmpeg-devel] [PATCH] h264: expose stereo_mode from h264 frame packing info
Joakim Plate
elupus at ecce.se
Sun Jun 23 15:19:45 CEST 2013
---
libavcodec/avcodec.h | 6 ++++
libavcodec/h264.c | 1 +
libavcodec/h264.h | 27 +++++++++++++++-
libavcodec/h264_parser.c | 3 ++
libavcodec/h264_sei.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 117 insertions(+), 1 deletion(-)
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 455f57b..1576524 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2874,6 +2874,12 @@ typedef struct AVCodecContext {
#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself
#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv
+ /**
+ * Stereoscopic mode of video (see matroska spec for definition)
+ * - decoding: set by libavcodec
+ * - encoding: unused
+ */
+ const char *stereo_mode;
} AVCodecContext;
AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx);
diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index bb105ee..2dc0f35 100644
--- a/libavcodec/h264.c
+++ b/libavcodec/h264.c
@@ -3304,6 +3304,7 @@ static int decode_slice_header(H264Context *h, H264Context *h0)
h->avctx->profile = ff_h264_get_profile(&h->sps);
h->avctx->level = h->sps.level_idc;
h->avctx->refs = h->sps.ref_frame_count;
+ h->avctx->stereo_mode = ff_h264_sei_stereo_mode(h);
must_reinit = (h->context_initialized &&
( 16*h->sps.mb_width != h->avctx->coded_width
diff --git a/libavcodec/h264.h b/libavcodec/h264.h
index ed07ad6..3fb4a53 100644
--- a/libavcodec/h264.h
+++ b/libavcodec/h264.h
@@ -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;
/**
@@ -146,6 +147,20 @@ typedef enum {
} SEI_PicStructType;
/**
+ * frame_packing_arrangement types
+ */
+typedef enum {
+ SEI_FPA_TYPE_NONE = -1,
+ 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 {
@@ -628,6 +643,10 @@ typedef struct H264Context {
*/
int valid_recovery_point;
+ int sei_fpa_content_interpretation_type;
+ SEI_FpaType sei_frame_packing_arrangement_type;
+
+
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 +794,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/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
index 3b7d011..f7e946b 100644
--- a/libavcodec/h264_parser.c
+++ b/libavcodec/h264_parser.c
@@ -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_frame_packing_arrangement_type = SEI_FPA_TYPE_NONE;
if (!buf_size)
return 0;
@@ -350,6 +351,8 @@ static inline int parse_nal_units(AVCodecParserContext *s,
s->field_order = AV_FIELD_UNKNOWN;
}
+ avctx->stereo_mode = ff_h264_sei_stereo_mode(h);
+
return 0; /* no need to evaluate the rest */
}
buf += h->is_avc ? nalsize : consumed;
diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c
index 5f68a13..99cb359 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_arrangement_type = SEI_FPA_TYPE_NONE;
}
static int decode_picture_timing(H264Context *h){
@@ -204,6 +205,45 @@ static int decode_buffering_period(H264Context *h){
return 0;
}
+static int decode_frame_packing(H264Context *h, int size){
+ int quincunx_sampling_flag, frame_packing_arrangement_cancel_flag, bits;
+
+ bits = get_bits_left(&h->gb);
+
+ get_ue_golomb(&h->gb) /* frame_packing_arrangement_id */;
+ frame_packing_arrangement_cancel_flag = get_bits(&h->gb, 1);
+ if (frame_packing_arrangement_cancel_flag) {
+ h->sei_frame_packing_arrangement_type = SEI_FPA_TYPE_NONE;
+ } else {
+ h->sei_frame_packing_arrangement_type = get_bits(&h->gb, 7);
+ 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 (!quincunx_sampling_flag && h->sei_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\n",
+ h->sei_frame_packing_arrangement_type,
+ h->sei_fpa_content_interpretation_type,
+ quincunx_sampling_flag);
+ 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;
@@ -246,6 +286,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 +299,41 @@ int ff_h264_decode_sei(H264Context *h){
return 0;
}
+
+const char* ff_h264_sei_stereo_mode(H264Context *h)
+{
+ switch (h->sei_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";
+ default:
+ return NULL;
+ }
+}
--
1.8.2
More information about the ffmpeg-devel
mailing list