[FFmpeg-devel] [PATCH] diracdec: add support for field coding

Rostislav Pehlivanov atomnuker at gmail.com
Tue Jan 26 12:40:43 CET 2016


This commit adds support for field coding (instead of the traditional
frame coding). In this mode, two fields, each half height, are
transmitted. The decoder does not output a frame for the first field
(the top one since Dirac only supports top field first) but caches it
and interleaves the image during the second field.

Tested with both the unmerged native Dirac encoder and the reference
implementations, both work.

Signed-off-by: Rostislav Pehlivanov <atomnuker at gmail.com>
---
 libavcodec/dirac.c    | 15 +++----------
 libavcodec/dirac.h    |  1 +
 libavcodec/diracdec.c | 59 +++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/libavcodec/dirac.c b/libavcodec/dirac.c
index 39df2a8..d19adcf 100644
--- a/libavcodec/dirac.c
+++ b/libavcodec/dirac.c
@@ -324,7 +324,7 @@ int av_dirac_parse_sequence_header(AVDiracSeqHeader **pdsh,
 {
     AVDiracSeqHeader *dsh;
     GetBitContext gb;
-    unsigned video_format, picture_coding_mode;
+    unsigned video_format;
     int ret;
 
     dsh = av_mallocz(sizeof(*dsh));
@@ -373,17 +373,8 @@ int av_dirac_parse_sequence_header(AVDiracSeqHeader **pdsh,
     if (ret < 0)
         goto fail;
 
-    /* [DIRAC_STD] picture_coding_mode shall be 0 for fields and 1 for frames
-     * currently only used to signal field coding */
-    picture_coding_mode = svq3_get_ue_golomb(&gb);
-    if (picture_coding_mode != 0) {
-        if (log_ctx) {
-            av_log(log_ctx, AV_LOG_ERROR, "Unsupported picture coding mode %d",
-                   picture_coding_mode);
-        }
-        ret = AVERROR_INVALIDDATA;
-        goto fail;
-    }
+    /* [DIRAC_STD] picture_coding_mode shall be 1 for fields and 0 for frames */
+    dsh->field_coding       = svq3_get_ue_golomb(&gb);
 
     *pdsh = dsh;
     return 0;
diff --git a/libavcodec/dirac.h b/libavcodec/dirac.h
index cb80fdc..447fafc 100644
--- a/libavcodec/dirac.h
+++ b/libavcodec/dirac.h
@@ -74,6 +74,7 @@ typedef struct AVDiracSeqHeader {
 
     uint8_t interlaced;
     uint8_t top_field_first;
+    uint8_t field_coding;
 
     uint8_t frame_rate_index;       ///< index into dirac_frame_rate[]
     uint8_t aspect_ratio_index;     ///< index into dirac_aspect_ratio[]
diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c
index ca44e7b..2f320a4 100644
--- a/libavcodec/diracdec.c
+++ b/libavcodec/diracdec.c
@@ -161,6 +161,8 @@ typedef struct DiracContext {
     int dc_prediction;          /* has dc prediction                         */
     int globalmc_flag;          /* use global motion compensation            */
     int num_refs;               /* number of reference pictures              */
+    int field_coding;           /* fields instead of frames                  */
+    int cur_field;              /* 0 -> progressive/top, 1 -> bottom         */
 
     /* wavelet decoding */
     unsigned wavelet_depth;     /* depth of the IDWT                         */
@@ -227,6 +229,7 @@ typedef struct DiracContext {
     dirac_weight_func weight_func;
     dirac_biweight_func biweight_func;
 
+    AVFrame *prev_field;
     DiracFrame *current_picture;
     DiracFrame *ref_pics[2];
 
@@ -1838,13 +1841,21 @@ static int dirac_decode_frame_internal(DiracContext *s)
             return ret;
 
         if (!s->num_refs) { /* intra */
-            for (y = 0; y < p->height; y += 16) {
-                int idx = (s->bit_depth - 8) >> 1;
-                ff_spatial_idwt_slice2(&d, y+16); /* decode */
-                s->diracdsp.put_signed_rect_clamped[idx](frame + y*p->stride,
-                                                         p->stride,
-                                                         p->idwt_buf + y*p->idwt_stride,
-                                                         p->idwt_stride, p->width, 16);
+            const int idx = (s->bit_depth - 8) >> 1;
+            const int ostride = p->stride*(1 + s->field_coding);
+            for (y = 0; y < p->height; y += 16)
+                ff_spatial_idwt_slice2(&d, y+16);
+            s->diracdsp.put_signed_rect_clamped[idx](frame + s->cur_field*p->stride,
+                                                     ostride, p->idwt_buf,
+                                                     p->idwt_stride, p->width,
+                                                     p->height);
+            if (s->field_coding && s->cur_field) { /* Copy the top field */
+                int x, y;
+                uint8_t *src = s->prev_field->data[comp];
+                for (y = 0; y < p->height; y++) {
+                    for (x = 0; x < p->width*2; x++)
+                        frame[p->stride*y*2 + x] = src[p->stride*y*2 + x];
+                }
             }
         } else { /* inter */
             int rowheight = p->ybsep*p->stride;
@@ -2070,6 +2081,10 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int
         }
 
         ret = ff_set_dimensions(avctx, dsh->width, dsh->height);
+
+        if (dsh->field_coding)
+            dsh->height >>= 1;
+
         if (ret < 0) {
             av_freep(&dsh);
             return ret;
@@ -2084,6 +2099,8 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int
         avctx->profile         = dsh->profile;
         avctx->level           = dsh->level;
         avctx->framerate       = dsh->framerate;
+        avctx->field_order     = dsh->top_field_first ? AV_FIELD_TT : avctx->field_order;
+        s->field_coding        = dsh->field_coding;
         s->bit_depth           = dsh->bit_depth;
         s->version.major       = dsh->version.major;
         s->version.minor       = dsh->version.minor;
@@ -2154,6 +2171,11 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int
             return AVERROR_INVALIDDATA;
         }
 
+        if (s->field_coding && !s->hq_picture) {
+            av_log(avctx, AV_LOG_ERROR, "Interlaced input supported only under the HQ profile!\n");
+            return AVERROR_PATCHWELCOME;
+        }
+
         if ((ret = get_buffer_with_edge(avctx, pic->avframe, (parse_code & 0x0C) == 0x0C ? AV_GET_BUFFER_FLAG_REF : 0)) < 0)
             return ret;
         s->current_picture = pic;
@@ -2233,6 +2255,29 @@ static int dirac_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
         buf_idx += data_unit_size;
     }
 
+    if (s->field_coding) {
+        s->current_picture->avframe->interlaced_frame = s->field_coding;
+        s->current_picture->avframe->top_field_first = avctx->field_order == AV_FIELD_TT;
+
+        if((ret=av_frame_ref(data, s->current_picture->avframe)) < 0)
+            return ret;
+
+        if (s->current_picture->avframe->display_picture_number & 1) {
+            s->cur_field = 0;
+            *got_frame = 1;
+            av_frame_free(&s->prev_field);
+        } else { /* Even number -> top field */
+            s->cur_field = 1;
+            *got_frame = 0;
+            s->prev_field = av_frame_clone(data);
+            av_frame_copy(s->prev_field, data);
+        }
+
+        s->frame_number++;
+
+        return buf_idx;
+    }
+
     if (!s->current_picture)
         return buf_size;
 
-- 
2.7.0



More information about the ffmpeg-devel mailing list