---

This did not save quite as many lines as I had hoped for, but it's a start..

 libavcodec/Makefile  |    2 +-
 libavcodec/h264.c    |  358 +++-----------------------------------------------
 libavcodec/h264.h    |    5 +
 libavcodec/h264dec.c |  349 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 375 insertions(+), 339 deletions(-)
 create mode 100644 libavcodec/h264dec.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 4dc218a..cbdaf33 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -179,7 +179,7 @@ OBJS-$(CONFIG_H263_ENCODER)            += mpegvideo_enc.o 
mpeg4video.o      \
                                           ratecontrol.o h263.o ituh263enc.o \
                                           flvenc.o mpeg12data.o             \
                                           mpegvideo.o error_resilience.o
-OBJS-$(CONFIG_H264_DECODER)            += h264.o                               
\
+OBJS-$(CONFIG_H264_DECODER)            += h264dec.o h264.o                     
\
                                           h264_loopfilter.o h264_direct.o      
\
                                           cabac.o h264_sei.o h264_ps.o         
\
                                           h264_refs.o h264_cavlc.o 
h264_cabac.o\
diff --git a/libavcodec/h264.c b/libavcodec/h264.c
index 787d0dc..66d97d8 100644
--- a/libavcodec/h264.c
+++ b/libavcodec/h264.c
@@ -34,9 +34,7 @@
 #include "mpegvideo.h"
 #include "h264.h"
 #include "h264data.h"
-#include "h264_mvpred.h"
 #include "golomb.h"
-#include "mathops.h"
 #include "rectangle.h"
 #include "thread.h"
 #include "vdpau_internal.h"
@@ -1094,7 +1092,7 @@ static void clone_tables(H264Context *dst, H264Context 
*src, int i)
  * Init context
  * Allocate buffers which are not shared amongst multiple threads.
  */
-static int context_init(H264Context *h)
+int ff_h264_context_init(H264Context *h)
 {
     FF_ALLOCZ_OR_GOTO(h->s.avctx, h->top_borders[0],
                       h->s.mb_width * 16 * 3 * sizeof(uint8_t) * 2, fail)
@@ -1114,8 +1112,6 @@ fail:
     return -1; // free_tables will clean up for us
 }
 
-static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size);
-
 static av_cold void common_init(H264Context *h)
 {
     MpegEncContext *const s = &h->s;
@@ -1161,7 +1157,7 @@ int ff_h264_decode_extradata(H264Context *h)
             nalsize = AV_RB16(p) + 2;
             if (p - avctx->extradata + nalsize > avctx->extradata_size)
                 return -1;
-            if (decode_nal_units(h, p, nalsize) < 0) {
+            if (ff_h264_decode_nal_units(h, p, nalsize) < 0) {
                 av_log(avctx, AV_LOG_ERROR,
                        "Decoding sps %d from avcC failed\n", i);
                 return -1;
@@ -1174,7 +1170,7 @@ int ff_h264_decode_extradata(H264Context *h)
             nalsize = AV_RB16(p) + 2;
             if (p - avctx->extradata + nalsize > avctx->extradata_size)
                 return -1;
-            if (decode_nal_units(h, p, nalsize) < 0) {
+            if (ff_h264_decode_nal_units(h, p, nalsize) < 0) {
                 av_log(avctx, AV_LOG_ERROR,
                        "Decoding pps %d from avcC failed\n", i);
                 return -1;
@@ -1185,7 +1181,8 @@ int ff_h264_decode_extradata(H264Context *h)
         h->nal_length_size = (avctx->extradata[4] & 0x03) + 1;
     } else {
         h->is_avc = 0;
-        if (decode_nal_units(h, avctx->extradata, avctx->extradata_size) < 0)
+        if (ff_h264_decode_nal_units(h, avctx->extradata,
+                                     avctx->extradata_size) < 0)
             return -1;
     }
     return 0;
@@ -1244,158 +1241,6 @@ av_cold int ff_h264_decode_init(AVCodecContext *avctx)
     return 0;
 }
 
-#define IN_RANGE(a, b, size) (((a) >= (b)) && ((a) < ((b) + (size))))
-
-static void copy_picture_range(Picture **to, Picture **from, int count,
-                               MpegEncContext *new_base,
-                               MpegEncContext *old_base)
-{
-    int i;
-
-    for (i = 0; i < count; i++) {
-        assert((IN_RANGE(from[i], old_base, sizeof(*old_base)) ||
-                IN_RANGE(from[i], old_base->picture,
-                         sizeof(Picture) * old_base->picture_count) ||
-                !from[i]));
-        to[i] = REBASE_PICTURE(from[i], new_base, old_base);
-    }
-}
-
-static void copy_parameter_set(void **to, void **from, int count, int size)
-{
-    int i;
-
-    for (i = 0; i < count; i++) {
-        if (to[i] && !from[i])
-            av_freep(&to[i]);
-        else if (from[i] && !to[i])
-            to[i] = av_malloc(size);
-
-        if (from[i])
-            memcpy(to[i], from[i], size);
-    }
-}
-
-static int decode_init_thread_copy(AVCodecContext *avctx)
-{
-    H264Context *h = avctx->priv_data;
-
-    if (!avctx->internal->is_copy)
-        return 0;
-    memset(h->sps_buffers, 0, sizeof(h->sps_buffers));
-    memset(h->pps_buffers, 0, sizeof(h->pps_buffers));
-
-    return 0;
-}
-
-#define copy_fields(to, from, start_field, end_field)                   \
-    memcpy(&to->start_field, &from->start_field,                        \
-           (char *)&to->end_field - (char *)&to->start_field)
-
-static int decode_update_thread_context(AVCodecContext *dst,
-                                        const AVCodecContext *src)
-{
-    H264Context *h = dst->priv_data, *h1 = src->priv_data;
-    MpegEncContext *const s = &h->s, *const s1 = &h1->s;
-    int inited = s->context_initialized, err;
-    int i;
-
-    if (dst == src || !s1->context_initialized)
-        return 0;
-
-    err = ff_mpeg_update_thread_context(dst, src);
-    if (err)
-        return err;
-
-    // FIXME handle width/height changing
-    if (!inited) {
-        for (i = 0; i < MAX_SPS_COUNT; i++)
-            av_freep(h->sps_buffers + i);
-
-        for (i = 0; i < MAX_PPS_COUNT; i++)
-            av_freep(h->pps_buffers + i);
-
-        // copy all fields after MpegEnc
-        memcpy(&h->s + 1, &h1->s + 1,
-               sizeof(H264Context) - sizeof(MpegEncContext));
-        memset(h->sps_buffers, 0, sizeof(h->sps_buffers));
-        memset(h->pps_buffers, 0, sizeof(h->pps_buffers));
-        if (ff_h264_alloc_tables(h) < 0) {
-            av_log(dst, AV_LOG_ERROR, "Could not allocate memory for h264\n");
-            return AVERROR(ENOMEM);
-        }
-        context_init(h);
-
-        for (i = 0; i < 2; i++) {
-            h->rbsp_buffer[i]      = NULL;
-            h->rbsp_buffer_size[i] = 0;
-        }
-
-        h->thread_context[0] = h;
-
-        /* frame_start may not be called for the next thread (if it's decoding
-         * a bottom field) so this has to be allocated here */
-        h->s.obmc_scratchpad = av_malloc(16 * 6 * s->linesize);
-
-        s->dsp.clear_blocks(h->mb);
-        s->dsp.clear_blocks(h->mb + (24 * 16 << h->pixel_shift));
-    }
-
-    // extradata/NAL handling
-    h->is_avc = h1->is_avc;
-
-    // SPS/PPS
-    copy_parameter_set((void **)h->sps_buffers, (void **)h1->sps_buffers,
-                       MAX_SPS_COUNT, sizeof(SPS));
-    h->sps = h1->sps;
-    copy_parameter_set((void **)h->pps_buffers, (void **)h1->pps_buffers,
-                       MAX_PPS_COUNT, sizeof(PPS));
-    h->pps = h1->pps;
-
-    // Dequantization matrices
-    // FIXME these are big - can they be only copied when PPS changes?
-    copy_fields(h, h1, dequant4_buffer, dequant4_coeff);
-
-    for (i = 0; i < 6; i++)
-        h->dequant4_coeff[i] = h->dequant4_buffer[0] +
-                               (h1->dequant4_coeff[i] - 
h1->dequant4_buffer[0]);
-
-    for (i = 0; i < 6; i++)
-        h->dequant8_coeff[i] = h->dequant8_buffer[0] +
-                               (h1->dequant8_coeff[i] - 
h1->dequant8_buffer[0]);
-
-    h->dequant_coeff_pps = h1->dequant_coeff_pps;
-
-    // POC timing
-    copy_fields(h, h1, poc_lsb, redundant_pic_count);
-
-    // reference lists
-    copy_fields(h, h1, ref_count, list_count);
-    copy_fields(h, h1, ref_list, intra_gb);
-    copy_fields(h, h1, short_ref, cabac_init_idc);
-
-    copy_picture_range(h->short_ref, h1->short_ref, 32, s, s1);
-    copy_picture_range(h->long_ref, h1->long_ref, 32, s, s1);
-    copy_picture_range(h->delayed_pic, h1->delayed_pic,
-                       MAX_DELAYED_PIC_COUNT + 2, s, s1);
-
-    h->last_slice_type = h1->last_slice_type;
-
-    if (!s->current_picture_ptr)
-        return 0;
-
-    if (!s->dropable) {
-        err = ff_h264_execute_ref_pic_marking(h, h->mmco, h->mmco_index);
-        h->prev_poc_msb = h->poc_msb;
-        h->prev_poc_lsb = h->poc_lsb;
-    }
-    h->prev_frame_num_offset = h->frame_num_offset;
-    h->prev_frame_num        = h->frame_num;
-    h->outputed_poc          = h->next_outputed_poc;
-
-    return err;
-}
-
 int ff_h264_frame_start(H264Context *h)
 {
     MpegEncContext *const s = &h->s;
@@ -1409,7 +1254,7 @@ int ff_h264_frame_start(H264Context *h)
      * ff_MPV_frame_start uses pict_type to derive key_frame.
      * This is incorrect for H.264; IDR markings must be used.
      * Zero here; IDR markings per slice in frame or fields are ORed in later.
-     * See decode_nal_units().
+     * See ff_h264_decode_nal_units().
      */
     s->current_picture_ptr->f.key_frame = 0;
     s->current_picture_ptr->mmco_reset  = 0;
@@ -1468,7 +1313,7 @@ int ff_h264_frame_start(H264Context *h)
  * @param setup_finished enough NALs have been read that we can call
  * ff_thread_finish_setup()
  */
-static void decode_postinit(H264Context *h, int setup_finished)
+void ff_h264_decode_postinit(H264Context *h, int setup_finished)
 {
     MpegEncContext *const s = &h->s;
     Picture *out = s->current_picture_ptr;
@@ -1485,8 +1330,8 @@ static void decode_postinit(H264Context *h, int 
setup_finished)
     if (cur->field_poc[0] == INT_MAX || cur->field_poc[1] == INT_MAX) {
         /* FIXME: if we have two PAFF fields in one packet, we can't start
          * the next thread here. If we have one field per packet, we can.
-         * The check in decode_nal_units() is not good enough to find this
-         * yet, so we assume the worst for now. */
+         * The check in ff_h264_ decode_nal_units() is not good enough to
+         * find this yet, so we assume the worst for now. */
         // if (setup_finished)
         //    ff_thread_finish_setup(s->avctx);
         return;
@@ -2602,7 +2447,7 @@ static void idr(H264Context *h)
 }
 
 /* forget old pics after a seek */
-static void flush_dpb(AVCodecContext *avctx)
+void ff_h264_flush_dpb(AVCodecContext *avctx)
 {
     H264Context *h = avctx->priv_data;
     int i;
@@ -2739,7 +2584,7 @@ static void init_scan_tables(H264Context *h)
     }
 }
 
-static int field_end(H264Context *h, int in_setup)
+int ff_h264_field_end(H264Context *h, int in_setup)
 {
     MpegEncContext *const s     = &h->s;
     AVCodecContext *const avctx = s->avctx;
@@ -2886,7 +2731,7 @@ static int decode_slice_header(H264Context *h, 
H264Context *h0)
 
     if (first_mb_in_slice == 0) { // FIXME better field boundary detection
         if (h0->current_slice && FIELD_PICTURE) {
-            field_end(h, 1);
+            ff_h264_field_end(h, 1);
         }
 
         h0->current_slice = 0;
@@ -2971,7 +2816,7 @@ static int decode_slice_header(H264Context *h, 
H264Context *h0)
             return -1;   // width / height changed during parallelized decoding
         }
         free_tables(h, 0);
-        flush_dpb(s->avctx);
+        ff_h264_flush_dpb(s->avctx);
         ff_MPV_common_end(s);
     }
     if (!s->context_initialized) {
@@ -3069,8 +2914,9 @@ static int decode_slice_header(H264Context *h, 
H264Context *h0)
         }
 
         if (!HAVE_THREADS || !(s->avctx->active_thread_type & 
FF_THREAD_SLICE)) {
-            if (context_init(h) < 0) {
-                av_log(h->s.avctx, AV_LOG_ERROR, "context_init() failed.\n");
+            if (ff_h264_context_init(h) < 0) {
+                av_log(h->s.avctx, AV_LOG_ERROR,
+                       "ff_h264_context_init() failed.\n");
                 return -1;
             }
         } else {
@@ -3088,9 +2934,9 @@ static int decode_slice_header(H264Context *h, 
H264Context *h0)
             }
 
             for (i = 0; i < s->slice_context_count; i++)
-                if (context_init(h->thread_context[i]) < 0) {
+                if (ff_h264_context_init(h->thread_context[i]) < 0) {
                     av_log(h->s.avctx, AV_LOG_ERROR,
-                           "context_init() failed.\n");
+                           "ff_h264_context_init() failed.\n");
                     return -1;
                 }
         }
@@ -4144,7 +3990,7 @@ static int execute_decode_slices(H264Context *h, int 
context_count)
     return 0;
 }
 
-static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
+int ff_h264_decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size)
 {
     MpegEncContext *const s     = &h->s;
     AVCodecContext *const avctx = s->avctx;
@@ -4289,7 +4135,7 @@ again:
 
                 if (h->current_slice == 1) {
                     if (!(s->flags2 & CODEC_FLAG2_CHUNKS))
-                        decode_postinit(h, nal_index >= nals_needed);
+                        ff_h264_decode_postinit(h, nal_index >= nals_needed);
 
                     if (s->avctx->hwaccel &&
                         s->avctx->hwaccel->start_frame(s->avctx, NULL, 0) < 0)
@@ -4449,103 +4295,6 @@ end:
     return buf_index;
 }
 
-/**
- * Return the number of bytes consumed for building the current frame.
- */
-static int get_consumed_bytes(MpegEncContext *s, int pos, int buf_size)
-{
-    if (pos == 0)
-        pos = 1;          // avoid infinite loops (i doubt that is needed but 
...)
-    if (pos + 10 > buf_size)
-        pos = buf_size;                   // oops ;)
-
-    return pos;
-}
-
-static int decode_frame(AVCodecContext *avctx, void *data,
-                        int *data_size, AVPacket *avpkt)
-{
-    const uint8_t *buf = avpkt->data;
-    int buf_size       = avpkt->size;
-    H264Context *h     = avctx->priv_data;
-    MpegEncContext *s  = &h->s;
-    AVFrame *pict      = data;
-    int buf_index      = 0;
-
-    s->flags  = avctx->flags;
-    s->flags2 = avctx->flags2;
-
-    /* end of stream, output what is still in the buffers */
-out:
-    if (buf_size == 0) {
-        Picture *out;
-        int i, out_idx;
-
-        s->current_picture_ptr = NULL;
-
-        // FIXME factorize this with the output code below
-        out     = h->delayed_pic[0];
-        out_idx = 0;
-        for (i = 1;
-             h->delayed_pic[i] &&
-             !h->delayed_pic[i]->f.key_frame &&
-             !h->delayed_pic[i]->mmco_reset;
-             i++)
-            if (h->delayed_pic[i]->poc < out->poc) {
-                out     = h->delayed_pic[i];
-                out_idx = i;
-            }
-
-        for (i = out_idx; h->delayed_pic[i]; i++)
-            h->delayed_pic[i] = h->delayed_pic[i + 1];
-
-        if (out) {
-            *data_size = sizeof(AVFrame);
-            *pict      = out->f;
-        }
-
-        return buf_index;
-    }
-
-    buf_index = decode_nal_units(h, buf, buf_size);
-    if (buf_index < 0)
-        return -1;
-
-    if (!s->current_picture_ptr && h->nal_unit_type == NAL_END_SEQUENCE) {
-        buf_size = 0;
-        goto out;
-    }
-
-    if (!(s->flags2 & CODEC_FLAG2_CHUNKS) && !s->current_picture_ptr) {
-        if (avctx->skip_frame >= AVDISCARD_NONREF)
-            return 0;
-        av_log(avctx, AV_LOG_ERROR, "no frame!\n");
-        return -1;
-    }
-
-    if (!(s->flags2 & CODEC_FLAG2_CHUNKS) ||
-        (s->mb_y >= s->mb_height && s->mb_height)) {
-        if (s->flags2 & CODEC_FLAG2_CHUNKS)
-            decode_postinit(h, 1);
-
-        field_end(h, 0);
-
-        if (!h->next_output_pic) {
-            /* Wait for second field. */
-            *data_size = 0;
-        } else {
-            *data_size = sizeof(AVFrame);
-            *pict      = h->next_output_pic->f;
-        }
-    }
-
-    assert(pict->data[0] || !*data_size);
-    ff_print_debug_info(s, pict);
-    // printf("out %d\n", (int)pict->data[0]);
-
-    return get_consumed_bytes(s, buf_index, buf_size);
-}
-
 av_cold void ff_h264_free_context(H264Context *h)
 {
     int i;
@@ -4558,70 +4307,3 @@ av_cold void ff_h264_free_context(H264Context *h)
     for (i = 0; i < MAX_PPS_COUNT; i++)
         av_freep(h->pps_buffers + i);
 }
-
-static av_cold int decode_end(AVCodecContext *avctx)
-{
-    H264Context *h    = avctx->priv_data;
-    MpegEncContext *s = &h->s;
-
-    ff_h264_free_context(h);
-
-    ff_MPV_common_end(s);
-
-    // memset(h, 0, sizeof(H264Context));
-
-    return 0;
-}
-
-static const AVProfile profiles[] = {
-    { FF_PROFILE_H264_BASELINE,             "Baseline"              },
-    { FF_PROFILE_H264_CONSTRAINED_BASELINE, "Constrained Baseline"  },
-    { FF_PROFILE_H264_MAIN,                 "Main"                  },
-    { FF_PROFILE_H264_EXTENDED,             "Extended"              },
-    { FF_PROFILE_H264_HIGH,                 "High"                  },
-    { FF_PROFILE_H264_HIGH_10,              "High 10"               },
-    { FF_PROFILE_H264_HIGH_10_INTRA,        "High 10 Intra"         },
-    { FF_PROFILE_H264_HIGH_422,             "High 4:2:2"            },
-    { FF_PROFILE_H264_HIGH_422_INTRA,       "High 4:2:2 Intra"      },
-    { FF_PROFILE_H264_HIGH_444,             "High 4:4:4"            },
-    { FF_PROFILE_H264_HIGH_444_PREDICTIVE,  "High 4:4:4 Predictive" },
-    { FF_PROFILE_H264_HIGH_444_INTRA,       "High 4:4:4 Intra"      },
-    { FF_PROFILE_H264_CAVLC_444,            "CAVLC 4:4:4"           },
-    { FF_PROFILE_UNKNOWN },
-};
-
-AVCodec ff_h264_decoder = {
-    .name                  = "h264",
-    .type                  = AVMEDIA_TYPE_VIDEO,
-    .id                    = CODEC_ID_H264,
-    .priv_data_size        = sizeof(H264Context),
-    .init                  = ff_h264_decode_init,
-    .close                 = decode_end,
-    .decode                = decode_frame,
-    .capabilities          = /*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 |
-                             CODEC_CAP_DELAY | CODEC_CAP_SLICE_THREADS |
-                             CODEC_CAP_FRAME_THREADS,
-    .flush                 = flush_dpb,
-    .long_name             = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / 
MPEG-4 part 10"),
-    .init_thread_copy      = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
-    .update_thread_context = 
ONLY_IF_THREADS_ENABLED(decode_update_thread_context),
-    .profiles              = NULL_IF_CONFIG_SMALL(profiles),
-};
-
-#if CONFIG_H264_VDPAU_DECODER
-AVCodec ff_h264_vdpau_decoder = {
-    .name           = "h264_vdpau",
-    .type           = AVMEDIA_TYPE_VIDEO,
-    .id             = CODEC_ID_H264,
-    .priv_data_size = sizeof(H264Context),
-    .init           = ff_h264_decode_init,
-    .close          = decode_end,
-    .decode         = decode_frame,
-    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_DELAY | 
CODEC_CAP_HWACCEL_VDPAU,
-    .flush          = flush_dpb,
-    .long_name      = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 
part 10 (VDPAU acceleration)"),
-    .pix_fmts       = (const enum PixelFormat[]) { PIX_FMT_VDPAU_H264,
-                                                   PIX_FMT_NONE},
-    .profiles       = NULL_IF_CONFIG_SMALL(profiles),
-};
-#endif
diff --git a/libavcodec/h264.h b/libavcodec/h264.h
index 99c46cc..2af6acf 100644
--- a/libavcodec/h264.h
+++ b/libavcodec/h264.h
@@ -662,8 +662,13 @@ int ff_h264_check_intra_pred_mode(H264Context *h, int 
mode, int is_chroma);
 void ff_h264_hl_decode_mb(H264Context *h);
 int ff_h264_frame_start(H264Context *h);
 int ff_h264_decode_extradata(H264Context *h);
+int ff_h264_decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size);
 av_cold int ff_h264_decode_init(AVCodecContext *avctx);
 av_cold void ff_h264_decode_init_vlc(void);
+int ff_h264_context_init(H264Context *h);
+void ff_h264_decode_postinit(H264Context *h, int setup_finished);
+void ff_h264_flush_dpb(AVCodecContext *avctx);
+int ff_h264_field_end(H264Context *h, int in_setup);
 
 /**
  * Decode a macroblock
diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c
new file mode 100644
index 0000000..e911c4e
--- /dev/null
+++ b/libavcodec/h264dec.c
@@ -0,0 +1,349 @@
+/*
+ * H.26L/H.264/AVC/JVT/14496-10/... decoder
+ * Copyright (c) 2003 Michael Niedermayer <[email protected]>
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * H.264 / AVC / MPEG4 part10 decoder
+ * @author Michael Niedermayer <[email protected]>
+ */
+
+#include "avcodec.h"
+#include "mpegvideo.h"
+#include "h264.h"
+
+// #undef NDEBUG
+#include <assert.h>
+
+#define IN_RANGE(a, b, size) (((a) >= (b)) && ((a) < ((b) + (size))))
+
+static void copy_picture_range(Picture **to, Picture **from, int count,
+                               MpegEncContext *new_base,
+                               MpegEncContext *old_base)
+{
+    int i;
+
+    for (i = 0; i < count; i++) {
+        assert((IN_RANGE(from[i], old_base, sizeof(*old_base)) ||
+                IN_RANGE(from[i], old_base->picture,
+                         sizeof(Picture) * old_base->picture_count) ||
+                !from[i]));
+        to[i] = REBASE_PICTURE(from[i], new_base, old_base);
+    }
+}
+
+static void copy_parameter_set(void **to, void **from, int count, int size)
+{
+    int i;
+
+    for (i = 0; i < count; i++) {
+        if (to[i] && !from[i])
+            av_freep(&to[i]);
+        else if (from[i] && !to[i])
+            to[i] = av_malloc(size);
+
+        if (from[i])
+            memcpy(to[i], from[i], size);
+    }
+}
+
+static int decode_init_thread_copy(AVCodecContext *avctx)
+{
+    H264Context *h = avctx->priv_data;
+
+    if (!avctx->internal->is_copy)
+        return 0;
+    memset(h->sps_buffers, 0, sizeof(h->sps_buffers));
+    memset(h->pps_buffers, 0, sizeof(h->pps_buffers));
+
+    return 0;
+}
+
+#define copy_fields(to, from, start_field, end_field)                   \
+    memcpy(&to->start_field, &from->start_field,                        \
+           (char *)&to->end_field - (char *)&to->start_field)
+
+static int decode_update_thread_context(AVCodecContext *dst,
+                                        const AVCodecContext *src)
+{
+    H264Context *h = dst->priv_data, *h1 = src->priv_data;
+    MpegEncContext *const s = &h->s, *const s1 = &h1->s;
+    int inited = s->context_initialized, err;
+    int i;
+
+    if (dst == src || !s1->context_initialized)
+        return 0;
+
+    err = ff_mpeg_update_thread_context(dst, src);
+    if (err)
+        return err;
+
+    // FIXME handle width/height changing
+    if (!inited) {
+        for (i = 0; i < MAX_SPS_COUNT; i++)
+            av_freep(h->sps_buffers + i);
+
+        for (i = 0; i < MAX_PPS_COUNT; i++)
+            av_freep(h->pps_buffers + i);
+
+        // copy all fields after MpegEnc
+        memcpy(&h->s + 1, &h1->s + 1,
+               sizeof(H264Context) - sizeof(MpegEncContext));
+        memset(h->sps_buffers, 0, sizeof(h->sps_buffers));
+        memset(h->pps_buffers, 0, sizeof(h->pps_buffers));
+        if (ff_h264_alloc_tables(h) < 0) {
+            av_log(dst, AV_LOG_ERROR, "Could not allocate memory for h264\n");
+            return AVERROR(ENOMEM);
+        }
+        ff_h264_context_init(h);
+
+        for (i = 0; i < 2; i++) {
+            h->rbsp_buffer[i]      = NULL;
+            h->rbsp_buffer_size[i] = 0;
+        }
+
+        h->thread_context[0] = h;
+
+        /* frame_start may not be called for the next thread (if it's decoding
+         * a bottom field) so this has to be allocated here */
+        h->s.obmc_scratchpad = av_malloc(16 * 6 * s->linesize);
+
+        s->dsp.clear_blocks(h->mb);
+        s->dsp.clear_blocks(h->mb + (24 * 16 << h->pixel_shift));
+    }
+
+    // extradata/NAL handling
+    h->is_avc = h1->is_avc;
+
+    // SPS/PPS
+    copy_parameter_set((void **)h->sps_buffers, (void **)h1->sps_buffers,
+                       MAX_SPS_COUNT, sizeof(SPS));
+    h->sps = h1->sps;
+    copy_parameter_set((void **)h->pps_buffers, (void **)h1->pps_buffers,
+                       MAX_PPS_COUNT, sizeof(PPS));
+    h->pps = h1->pps;
+
+    // Dequantization matrices
+    // FIXME these are big - can they be only copied when PPS changes?
+    copy_fields(h, h1, dequant4_buffer, dequant4_coeff);
+
+    for (i = 0; i < 6; i++)
+        h->dequant4_coeff[i] = h->dequant4_buffer[0] +
+                               (h1->dequant4_coeff[i] - 
h1->dequant4_buffer[0]);
+
+    for (i = 0; i < 6; i++)
+        h->dequant8_coeff[i] = h->dequant8_buffer[0] +
+                               (h1->dequant8_coeff[i] - 
h1->dequant8_buffer[0]);
+
+    h->dequant_coeff_pps = h1->dequant_coeff_pps;
+
+    // POC timing
+    copy_fields(h, h1, poc_lsb, redundant_pic_count);
+
+    // reference lists
+    copy_fields(h, h1, ref_count, list_count);
+    copy_fields(h, h1, ref_list, intra_gb);
+    copy_fields(h, h1, short_ref, cabac_init_idc);
+
+    copy_picture_range(h->short_ref, h1->short_ref, 32, s, s1);
+    copy_picture_range(h->long_ref, h1->long_ref, 32, s, s1);
+    copy_picture_range(h->delayed_pic, h1->delayed_pic,
+                       MAX_DELAYED_PIC_COUNT + 2, s, s1);
+
+    h->last_slice_type = h1->last_slice_type;
+
+    if (!s->current_picture_ptr)
+        return 0;
+
+    if (!s->dropable) {
+        err = ff_h264_execute_ref_pic_marking(h, h->mmco, h->mmco_index);
+        h->prev_poc_msb = h->poc_msb;
+        h->prev_poc_lsb = h->poc_lsb;
+    }
+    h->prev_frame_num_offset = h->frame_num_offset;
+    h->prev_frame_num        = h->frame_num;
+    h->outputed_poc          = h->next_outputed_poc;
+
+    return err;
+}
+
+/**
+ * Return the number of bytes consumed for building the current frame.
+ */
+static int get_consumed_bytes(MpegEncContext *s, int pos, int buf_size)
+{
+    if (pos == 0)
+        pos = 1;          // avoid infinite loops (i doubt that is needed but 
...)
+    if (pos + 10 > buf_size)
+        pos = buf_size;                   // oops ;)
+
+    return pos;
+}
+
+static int decode_frame(AVCodecContext *avctx, void *data,
+                        int *data_size, AVPacket *avpkt)
+{
+    const uint8_t *buf = avpkt->data;
+    int buf_size       = avpkt->size;
+    H264Context *h     = avctx->priv_data;
+    MpegEncContext *s  = &h->s;
+    AVFrame *pict      = data;
+    int buf_index      = 0;
+
+    s->flags  = avctx->flags;
+    s->flags2 = avctx->flags2;
+
+    /* end of stream, output what is still in the buffers */
+out:
+    if (buf_size == 0) {
+        Picture *out;
+        int i, out_idx;
+
+        s->current_picture_ptr = NULL;
+
+        // FIXME factorize this with the output code below
+        out     = h->delayed_pic[0];
+        out_idx = 0;
+        for (i = 1;
+             h->delayed_pic[i] &&
+             !h->delayed_pic[i]->f.key_frame &&
+             !h->delayed_pic[i]->mmco_reset;
+             i++)
+            if (h->delayed_pic[i]->poc < out->poc) {
+                out     = h->delayed_pic[i];
+                out_idx = i;
+            }
+
+        for (i = out_idx; h->delayed_pic[i]; i++)
+            h->delayed_pic[i] = h->delayed_pic[i + 1];
+
+        if (out) {
+            *data_size = sizeof(AVFrame);
+            *pict      = out->f;
+        }
+
+        return buf_index;
+    }
+
+    buf_index = ff_h264_decode_nal_units(h, buf, buf_size);
+    if (buf_index < 0)
+        return -1;
+
+    if (!s->current_picture_ptr && h->nal_unit_type == NAL_END_SEQUENCE) {
+        buf_size = 0;
+        goto out;
+    }
+
+    if (!(s->flags2 & CODEC_FLAG2_CHUNKS) && !s->current_picture_ptr) {
+        if (avctx->skip_frame >= AVDISCARD_NONREF)
+            return 0;
+        av_log(avctx, AV_LOG_ERROR, "no frame!\n");
+        return -1;
+    }
+
+    if (!(s->flags2 & CODEC_FLAG2_CHUNKS) ||
+        (s->mb_y >= s->mb_height && s->mb_height)) {
+        if (s->flags2 & CODEC_FLAG2_CHUNKS)
+            ff_h264_decode_postinit(h, 1);
+
+        ff_h264_field_end(h, 0);
+
+        if (!h->next_output_pic) {
+            /* Wait for second field. */
+            *data_size = 0;
+        } else {
+            *data_size = sizeof(AVFrame);
+            *pict      = h->next_output_pic->f;
+        }
+    }
+
+    assert(pict->data[0] || !*data_size);
+    ff_print_debug_info(s, pict);
+    // printf("out %d\n", (int)pict->data[0]);
+
+    return get_consumed_bytes(s, buf_index, buf_size);
+}
+
+static av_cold int decode_end(AVCodecContext *avctx)
+{
+    H264Context *h    = avctx->priv_data;
+    MpegEncContext *s = &h->s;
+
+    ff_h264_free_context(h);
+
+    ff_MPV_common_end(s);
+
+    // memset(h, 0, sizeof(H264Context));
+
+    return 0;
+}
+
+static const AVProfile profiles[] = {
+    { FF_PROFILE_H264_BASELINE,             "Baseline"              },
+    { FF_PROFILE_H264_CONSTRAINED_BASELINE, "Constrained Baseline"  },
+    { FF_PROFILE_H264_MAIN,                 "Main"                  },
+    { FF_PROFILE_H264_EXTENDED,             "Extended"              },
+    { FF_PROFILE_H264_HIGH,                 "High"                  },
+    { FF_PROFILE_H264_HIGH_10,              "High 10"               },
+    { FF_PROFILE_H264_HIGH_10_INTRA,        "High 10 Intra"         },
+    { FF_PROFILE_H264_HIGH_422,             "High 4:2:2"            },
+    { FF_PROFILE_H264_HIGH_422_INTRA,       "High 4:2:2 Intra"      },
+    { FF_PROFILE_H264_HIGH_444,             "High 4:4:4"            },
+    { FF_PROFILE_H264_HIGH_444_PREDICTIVE,  "High 4:4:4 Predictive" },
+    { FF_PROFILE_H264_HIGH_444_INTRA,       "High 4:4:4 Intra"      },
+    { FF_PROFILE_H264_CAVLC_444,            "CAVLC 4:4:4"           },
+    { FF_PROFILE_UNKNOWN },
+};
+
+AVCodec ff_h264_decoder = {
+    .name                  = "h264",
+    .type                  = AVMEDIA_TYPE_VIDEO,
+    .id                    = CODEC_ID_H264,
+    .priv_data_size        = sizeof(H264Context),
+    .init                  = ff_h264_decode_init,
+    .close                 = decode_end,
+    .decode                = decode_frame,
+    .capabilities          = /*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 |
+                             CODEC_CAP_DELAY | CODEC_CAP_SLICE_THREADS |
+                             CODEC_CAP_FRAME_THREADS,
+    .flush                 = ff_h264_flush_dpb,
+    .long_name             = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / 
MPEG-4 part 10"),
+    .init_thread_copy      = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
+    .update_thread_context = 
ONLY_IF_THREADS_ENABLED(decode_update_thread_context),
+    .profiles              = NULL_IF_CONFIG_SMALL(profiles),
+};
+
+#if CONFIG_H264_VDPAU_DECODER
+AVCodec ff_h264_vdpau_decoder = {
+    .name           = "h264_vdpau",
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = CODEC_ID_H264,
+    .priv_data_size = sizeof(H264Context),
+    .init           = ff_h264_decode_init,
+    .close          = decode_end,
+    .decode         = decode_frame,
+    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_DELAY | 
CODEC_CAP_HWACCEL_VDPAU,
+    .flush          = ff_h264_flush_dpb,
+    .long_name      = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 
part 10 (VDPAU acceleration)"),
+    .pix_fmts       = (const enum PixelFormat[]) { PIX_FMT_VDPAU_H264,
+                                                   PIX_FMT_NONE},
+    .profiles       = NULL_IF_CONFIG_SMALL(profiles),
+};
+#endif
-- 
1.7.1

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to