[FFmpeg-devel] [PATCH 3/6] h264_changesps_bsf: import code

Christophe Gisquet christophe.gisquet at gmail.com
Sun Nov 30 01:45:53 CET 2014


From: Zongyi Zhou <zhouzy at os.pku.edu.cn>

Mostly unverified, but seems to have been extensively tested here:
http://forum.doom9.org/showthread.php?t=152419

Signed-off-by: Christophe Gisquet <christophe.gisquet at gmail.com>
---
 libavcodec/Makefile             |   1 +
 libavcodec/allcodecs.c          |   1 +
 libavcodec/h264_changesps_bsf.c | 622 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 624 insertions(+)
 create mode 100644 libavcodec/h264_changesps_bsf.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index fa0f53d..8eecf51 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -820,6 +820,7 @@ OBJS-$(CONFIG_AAC_ADTSTOASC_BSF)          += aac_adtstoasc_bsf.o aacadtsdec.o \
                                              mpeg4audio.o
 OBJS-$(CONFIG_CHOMP_BSF)                  += chomp_bsf.o
 OBJS-$(CONFIG_DUMP_EXTRADATA_BSF)         += dump_extradata_bsf.o
+OBJS-$(CONFIG_H264_CHANGESPS_BSF)         += h264_changesps_bsf.o
 OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF)       += h264_mp4toannexb_bsf.o
 OBJS-$(CONFIG_IMX_DUMP_HEADER_BSF)        += imx_dump_header_bsf.o
 OBJS-$(CONFIG_MJPEG2JPEG_BSF)             += mjpeg2jpeg_bsf.o mjpeg.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 0d39d33..0380824 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -581,6 +581,7 @@ void avcodec_register_all(void)
     REGISTER_BSF(AAC_ADTSTOASC,         aac_adtstoasc);
     REGISTER_BSF(CHOMP,                 chomp);
     REGISTER_BSF(DUMP_EXTRADATA,        dump_extradata);
+    REGISTER_BSF(H264_CHANGESPS,        h264_changesps);
     REGISTER_BSF(H264_MP4TOANNEXB,      h264_mp4toannexb);
     REGISTER_BSF(IMX_DUMP_HEADER,       imx_dump_header);
     REGISTER_BSF(MJPEG2JPEG,            mjpeg2jpeg);
diff --git a/libavcodec/h264_changesps_bsf.c b/libavcodec/h264_changesps_bsf.c
new file mode 100644
index 0000000..5daea89
--- /dev/null
+++ b/libavcodec/h264_changesps_bsf.c
@@ -0,0 +1,622 @@
+/*
+ * H.264 change sps filter
+ * Copyright (c) 2010 Zongyi Zhou <zhouzy at os.pku.edu.cn>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg 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.
+ *
+ * FFmpeg 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 FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include "golomb.h"
+
+extern AVRational pixel_aspect[];
+
+// NAL unit types, copied from h264.h
+enum {
+    NAL_SLICE=1,
+    NAL_DPA,
+    NAL_DPB,
+    NAL_DPC,
+    NAL_IDR_SLICE,
+    NAL_SEI,
+    NAL_SPS,
+    NAL_PPS,
+    NAL_AUD,
+    NAL_END_SEQUENCE,
+    NAL_END_STREAM,
+    NAL_FILLER_DATA,
+    NAL_SPS_EXT,
+    NAL_AUXILIARY_SLICE=19
+};
+
+typedef struct H264SPSContext {
+    uint8_t state;
+    uint8_t bs_type; // 1=annexb 2=mp4
+    int8_t fps_mode;
+    int8_t remove_hrd;
+    int32_t fps_den, fps_num;
+    int32_t predefined_sar;
+    int32_t level;
+    int32_t refs;
+    uint32_t remove_nal_flags, delay_remove_flags;
+    int16_t sar_x, sar_y;
+    int16_t crop_x, crop_y;
+    int8_t fullrange, colorprim, transfer, colmatrix;
+} H264SPSContext;
+
+static int parse_args(struct H264SPSContext *c, const char *args)
+{
+    int r = 0;
+    int32_t sarx = -1, sary = -1, cropx = -1, cropy = -1, level = -1,
+            refs = -1, colorprim = -1, transfer = -1, colmatrix = -1;
+    if (!args) return 0;
+    c->fps_den = c->fps_num = c->fps_mode = -1;
+    c->fullrange = -1;
+    c->remove_nal_flags = c->delay_remove_flags = 0;
+    while (*args) {
+        if (sscanf(args, "fps=%u:%u", &c->fps_num, &c->fps_den) == 2 ||
+            sscanf(args, "sar=%u:%u", &sarx, &sary) == 2 ||
+            sscanf(args, "crop=%u:%u", &cropx, &cropy) == 2 ||
+            sscanf(args, "level=%u", &level) == 1 ||
+            sscanf(args, "ref=%u", &refs) == 1 ||
+            sscanf(args, "colorprim=%u", &colorprim) == 1 ||
+            sscanf(args, "transfer=%u", &transfer) == 1 ||
+            sscanf(args, "colormatrix=%u", &colmatrix) == 1)
+                r++;
+        else if (!strncmp(args, "vfr", 3)) {
+            r++;
+            c->fps_mode = 0;
+        } else if (!strncmp(args, "cfr", 3)) {
+            r++;
+            c->fps_mode = 1;
+        } else if (!strncmp(args, "fullrange", 9)) {
+            r++;
+            c->fullrange = 1;
+        } else if (!strncmp(args, "removesei", 9)) {
+            r++;
+            c->remove_nal_flags |= 1 << NAL_SEI;
+        } else if (!strncmp(args, "removeaud", 9)) {
+            r++;
+            c->remove_nal_flags |= 1 << NAL_AUD;
+        } else if (!strncmp(args, "limitedrange", 12)) {
+            r++;
+            c->fullrange = 0;
+        } else if (!strncmp(args, "removedupheader", 15)) {
+            r++;
+            c->delay_remove_flags |= (1 << NAL_SPS) + (1 << NAL_PPS);
+        }
+        if (!(args = strchr(args, '/'))) break;
+        args++;
+    }
+    if (sary == -1) sarx = -1;
+    if (cropy == -1) cropx = -1;
+    c->sar_x = sarx; c->sar_y = sary;
+    c->crop_x = cropx; c->crop_y = cropy;
+    c->level = level;
+    c->refs = refs;
+    c->colorprim = colorprim;
+    c->transfer = transfer;
+    c->colmatrix = colmatrix;
+    if (sarx && sary) {
+        int i;
+        c->predefined_sar = 255;
+        for (i = 1; i < 17; i++)
+            if (pixel_aspect[i].den * sarx == pixel_aspect[i].num * sary) {
+               c->predefined_sar = i;
+               break;
+            }
+    }
+    return r;
+}
+
+static void skip_hrd_param(GetBitContext *pgb)
+{
+    int t = get_ue_golomb_31(pgb);
+    skip_bits(pgb, 8);
+    for (t++;t;t--) {
+        get_ue_golomb(pgb);
+        get_ue_golomb(pgb);
+        skip_bits1(pgb);
+    }
+    skip_bits(pgb, 20);
+}
+
+static int nal_enc(uint8_t *dst, const uint8_t *src, int size)
+{
+    int i = 0;
+    uint8_t *dst_start = dst;
+    for(;size;size--) {
+        if( i == 2 && *src <= 3 ) {
+            *dst++ = 3;
+            i = 0;
+        }
+        if (*src == 0)
+            i++;
+        else
+            i = 0;
+        *dst++ = *src++;
+    }
+    return dst - dst_start;
+}
+
+static int nal_dec(uint8_t *dst, const uint8_t *src, int size)
+{
+    int i = 0;
+    uint8_t *dst_start = dst;
+    for(;size;size--) {
+        uint8_t t = *src++;
+        if (i == 2) {
+            i = 0;
+            if (t == 3)
+                continue;
+        }
+        if (t == 0)
+            i++;
+        else
+            i = 0;
+        *dst++ = t;
+    }
+    return dst - dst_start;
+}
+
+static void sl_copy(GetBitContext *pgb, PutBitContext *ppb, int size)
+{
+    int delta, next = 8, j;
+    for(j = 0;j < size && next;j++) {
+        delta = get_se_golomb(pgb);
+        set_se_golomb(ppb, delta);
+        next = (next + delta + 256) & 255;
+    }
+}
+
+static int h264_modify(uint8_t *outbuf, const uint8_t *inbuf, H264SPSContext *ctx, int insize)
+{
+    GetBitContext gb;
+    PutBitContext pb;
+#define COPYUE set_ue_golomb(&pb, get_ue_golomb(&gb))
+#define COPYUE31 set_ue_golomb(&pb, get_ue_golomb_31(&gb))
+#define COPYSE set_se_golomb(&pb, get_se_golomb(&gb))
+#define COPYBITS1 put_bits(&pb, 1, get_bits1(&gb))
+    int p, t, i;
+    init_get_bits(&gb, inbuf, insize * 8);
+    init_put_bits(&pb, outbuf, (insize + 10) * 8);
+    p = get_bits(&gb, 8); //profile_idc
+    put_bits(&pb, 8, p);
+    put_bits(&pb, 8, get_bits(&gb, 8)); //constraint_set
+    t = get_bits(&gb, 8); //level_idc
+    if (ctx->level != -1)
+        t = ctx->level;
+    put_bits(&pb, 8, t);
+    COPYUE31;
+    if (p >= 100) {
+        t = get_ue_golomb(&gb); //chroma_format_idc
+        set_ue_golomb(&pb, t);
+        if (t == 3)
+            COPYBITS1; //residue_transform_flag
+        COPYUE; //bit_depth_luma_minus8
+        COPYUE; //bit_depth_chroma_minus8
+        COPYBITS1; //qpprime_y_zero_transform_bypass_flag
+        t = get_bits1(&gb); //seq_scaling_matrix_present_flag
+        put_bits(&pb, 1, t);
+        if (t) {
+            //copy scaling list
+            for (i = 0;i < 8;i++) {
+                t = get_bits1(&gb);
+                put_bits(&pb, 1, t);
+                if (t)
+                    sl_copy(&gb, &pb, i < 6? 16 : 64);
+            }
+        }
+    }
+    COPYUE; //log2_max_frame_num-4
+    t = get_ue_golomb_31(&gb); //poc_type
+    set_ue_golomb(&pb, t);
+    if (t == 0) COPYUE; //log2_max_poc_lsb
+    else if (t == 1) {
+        COPYBITS1; //delta_pic_order_always_zero
+        COPYSE; //offset_for_non_ref_pic
+        COPYSE; //offset_for_top_to_bottom_field
+        t = get_ue_golomb(&gb); //num_ref_frames_in_poc_cycle
+        set_ue_golomb(&pb, t);
+        for (;t;t--) COPYUE;
+    }
+    //num_ref_frames
+    t = get_ue_golomb_31(&gb);
+    if (ctx->refs != -1)
+        t = ctx->refs;
+    set_ue_golomb(&pb,t);
+    COPYBITS1;
+    COPYUE;
+    COPYUE;
+    i = get_bits1(&gb); //frame_mbs_only
+    put_bits(&pb, 1, i);
+    if (!i) COPYBITS1;
+    COPYBITS1;
+
+    t = get_bits1(&gb);
+    if (ctx->crop_x == -1)
+        put_bits(&pb, 1, t);
+    if (t) {
+        int t1, t2, t3, t4;
+        t1 = get_ue_golomb(&gb),
+        t2 = get_ue_golomb(&gb),
+        t3 = get_ue_golomb(&gb),
+        t4 = get_ue_golomb(&gb);
+        if (ctx->crop_x == -1) {
+            set_ue_golomb(&pb, t1);
+            set_ue_golomb(&pb, t2);
+            set_ue_golomb(&pb, t3);
+            set_ue_golomb(&pb, t4);
+        }
+    }
+    if (ctx->crop_x != -1) {
+        if (ctx->crop_x || ctx->crop_y) {
+            put_bits(&pb, 1, 1);
+            set_ue_golomb(&pb, 0);
+            set_ue_golomb(&pb, (ctx->crop_x + 1) >> 1);
+            set_ue_golomb(&pb, 0);
+            set_ue_golomb(&pb, (ctx->crop_y + 1) >> (2 >> i));
+        } else put_bits(&pb, 1, 0);
+    }
+    t = get_bits1(&gb);
+    put_bits(&pb, 1, t);
+    if (t) {
+        int ch = ctx->sar_x != -1;
+        t = get_bits1(&gb);
+        if (!ch) put_bits(&pb, 1, t);
+        if (t) {
+            t = get_bits(&gb, 8);
+            if (!ch) put_bits(&pb, 8, t);
+            if (t == 255) {
+                t = get_bits(&gb, 16);
+                i = get_bits(&gb, 16);
+                if (!ch) {
+                    put_bits(&pb, 16, t);
+                    put_bits(&pb, 16, i);
+                }
+            }
+        }
+        if (ch) {
+            if (ctx->predefined_sar == 0) put_bits(&pb, 1, 0);
+            else {
+                put_bits(&pb, 1, 1);
+                if (ctx->predefined_sar < 17) put_bits(&pb, 8, ctx->predefined_sar);
+                else {
+                    put_bits(&pb, 8, 255);
+                    put_bits(&pb, 16, ctx->sar_x);
+                    put_bits(&pb, 16, ctx->sar_y);
+                }
+            }
+        }
+
+        t = get_bits1(&gb); //overscan_info_present_flag
+        put_bits(&pb, 1, t);
+        if (t) COPYBITS1;
+
+        p = ch = -1; i = 0;
+        t = get_bits1(&gb); //video_signal_type_present_flag
+        if (t) {
+            p = get_bits(&gb, 4); //video_format + video_full_range_flag
+            i = get_bits1(&gb); //colour_description_present_flag
+            if (i)
+                ch = get_bits(&gb, 24);
+        }
+        if (ctx->fullrange != -1)
+            p = ctx->fullrange | (p == -1? 5<<1 : p&~1);
+        if (ctx->colorprim != -1)
+            ch = (ctx->colorprim<<16) | (ch == -1? (2<<8)|2 : ch&0xFFFF);
+        if (ctx->transfer != -1)
+            ch = (ctx->transfer<<8) | (ch == -1? (2<<16)|2 : ch&0xFF00FF);
+        if (ctx->colmatrix != -1)
+            ch = ctx->colmatrix | (ch == -1? (2<<16)|(2<<8) : ch&0xFFFF00);
+        if (p != -1 || ch != -1)
+            t = 1;
+        put_bits(&pb, 1, t);
+        if (t) {
+            if (p == -1)
+                p = 5; //undef
+            put_bits(&pb, 4 ,p);
+            if (ch != -1)
+                i = 1;
+            put_bits(&pb, 1, i);
+            if (i)
+                put_bits(&pb, 24, ch);
+        }
+
+        t = get_bits1(&gb); //chroma_location_info_present_flag
+        put_bits(&pb, 1, t);
+        if (t) {
+            COPYUE;
+            COPYUE;
+        }
+
+        t = get_bits1(&gb); //timing_info_present_flag
+        ch = ctx->fps_den != -1;
+        if (t) {
+            t = get_bits_long(&gb, 32),
+            i = get_bits_long(&gb, 32);
+            p = get_bits1(&gb);
+        }
+        if (ctx->fps_mode >= 0)
+            p = ctx->fps_mode;
+        if (ch) {
+            t = ctx->fps_den;
+            i = ctx->fps_num * 2;
+        }
+        if (t || p >= 0) {
+            put_bits(&pb, 1, 1);
+            put_bits(&pb, 32, t);
+            put_bits(&pb, 32, i);
+            put_bits(&pb, 1, p);
+        } else put_bits(&pb, 1, 0);
+        p = get_bits_count(&gb);
+        i = get_bits1(&gb); //nal_hrd_parameters_present_flag
+        if (i) skip_hrd_param(&gb);
+        t = get_bits1(&gb); //vcl_hrd_parameters_present_flag
+        if (t) skip_hrd_param(&gb);
+        if (i || t) skip_bits1(&gb); //low_delay_hrd_flag
+        p = get_bits_count(&gb) - p;
+        gb.index -= p;
+        for (;p > 24;p -= 24)
+            put_bits(&pb, 24, get_bits(&gb, 24));
+        put_bits(&pb, p, get_bits(&gb, p));
+        COPYBITS1; //pic_struct_present_flag
+        t = get_bits1(&gb); //bitstream_restriction_flag
+        put_bits(&pb, 1, t);
+        if (t) {
+            COPYBITS1;
+            COPYUE;
+            COPYUE;
+            COPYUE;
+            COPYUE;
+            COPYUE;
+            COPYUE;
+        }
+    }
+    COPYBITS1; //rbsp trailing
+    t = get_bits_count(&gb);
+    flush_put_bits(&pb);
+        t = (t + 7) >> 3;
+    i = put_bits_count(&pb) >> 3;
+    if (insize > t)
+        memcpy(outbuf + i, inbuf + t, insize - t);
+    return insize + i - t;
+}
+
+static int find_next_nal_annexb(const uint8_t *src, int *p, int size)
+{
+    int i = 0;
+    int j = *p;
+    for(;j<size;j++) {
+        uint8_t t = src[j];
+        if (i == 2) {
+            if (t == 1) {
+                *p = j + 1;
+                return src[j+1] & 0x1f;
+            } else if (t)
+                i = 0;
+        } else if (t == 0)
+            i++;
+        else
+            i = 0;
+    }
+    return 0;
+}
+
+static int h264_changesps_filter(AVBitStreamFilterContext *bsfc,
+                                 AVCodecContext *avctx, const char *args,
+                                 uint8_t  **poutbuf, int *poutbuf_size,
+                                 const uint8_t *buf, int      buf_size,
+                                 int keyframe)
+{
+    H264SPSContext *ctx = bsfc->priv_data;
+    static const uint8_t profile_level[256] = {
+        [66]  = 1, [77]  = 1, [88]  = 1, [100] = 1,
+        [110] = 1, [122] = 1, [144] = 1, [244] = 1,
+        [10] = 2, [11] = 2, [12] = 2, [13] = 2, [16] = 2, [20] = 2,
+        [21] = 2, [22] = 2, [30] = 2, [31] = 2, [32] = 2, [40] = 2,
+        [41] = 2, [42] = 2, [50] = 2, [51] = 2
+    };
+    uint8_t spsbuf0[64], spsbuf1[64]; // should be big enough
+    uint32_t spslen = 0;
+
+    *poutbuf = buf;
+    *poutbuf_size = buf_size;
+
+    if (avctx->codec_id != CODEC_ID_H264)
+        return 0;
+
+    if (!ctx->state) {
+        if (parse_args(ctx, args)) ctx->state = 1;
+        else {
+            ctx->state = 16;
+            return 0;
+        }
+    }
+
+    /* filter extradata */
+    if ((ctx->state & 1) && avctx->extradata && avctx->extradata_size > 5) {
+        uint8_t *data = avctx->extradata, *ndata;
+        int i = (data[5] & 0x1f)? 8 : 9;
+        int l = avctx->extradata_size;
+
+        if (AV_RB16(data)) {
+            for (;i < l-1;i++) {
+                if ((data[i] & 0x1f) == 7) {
+                    int t = data[i + 1];
+                    if (profile_level[t] > 0) break;
+                }
+            }
+            if (i < l-1) {
+                int r, m, d;
+                ndata = av_mallocz(l + 16);
+                i++;
+                memcpy(ndata, data, i);
+                d = l;
+                l = nal_dec(data + i, data + i, l - i) + i;
+                r = h264_modify(ndata + 8 + i, data + i, ctx, l - i);
+                r = nal_enc(ndata + i, ndata + 8 + i, r);
+                d = r + i - d;
+                avctx->extradata_size = r + i;
+                av_free(avctx->extradata);
+                avctx->extradata = ndata;
+                if (ctx->level != -1)
+                    ndata[3] = ctx->level;
+                m = (ndata[5] & 0x1f)? 6 : 7;
+                AV_WB16(ndata + m, AV_RB16(ndata + m) + d);
+                if (ctx->crop_x != -1) {
+                    avctx->width  = ((avctx->width  + 15) & ~15) - ctx->crop_x;
+                    avctx->height = ((avctx->height + 15) & ~15) - ctx->crop_y;
+                }
+                r = ctx->fps_num;
+                if (r > 0) {
+                    avctx->time_base.den = r;
+                    avctx->time_base.num = ctx->fps_den;
+                }
+                ctx->state = 6;
+            }
+            else ctx->state = 2;
+        }
+
+    }
+
+    // check bitstream type
+    if (!ctx->bs_type) {
+        if (buf && buf_size > 5) {
+            uint32_t t = AV_RB32(buf);
+            ctx->bs_type = 2;
+            if (t == 1)
+                ctx->bs_type = 1;
+            else if ((t & 0xFFFFFF00) == 0x0100) {
+                int i = 4;
+                if (find_next_nal_annexb(buf, &i, buf_size) > 0)
+                    ctx->bs_type = 1;
+            }
+        }
+        else
+            return 0;
+    }
+
+    if (ctx->remove_nal_flags || ctx->delay_remove_flags) {
+        int needmove = 0;
+        uint32_t i = 0, b = 0;
+        if (ctx->bs_type == 1) {
+            uint32_t t, j = 0;
+            int skip = 0;
+            while ((t = find_next_nal_annexb(buf, &i, buf_size)) && t != NAL_SLICE && t != NAL_IDR_SLICE) {
+                if (!skip){
+                    if (needmove)
+                        memmove(buf + b, buf + j, i - j);
+                    b += i - j;
+                }
+                if (ctx->remove_nal_flags & (1<<t)) {
+                    skip = 1;
+                    needmove = 1;
+                } else {
+                    skip = 0;
+                    if (ctx->delay_remove_flags & (1<<t))
+                        ctx->remove_nal_flags |= 1<<t;
+                }
+                j = i;
+            }
+            i = j;
+        } else {
+            uint32_t t, r;
+            ctx->remove_nal_flags |= ctx->delay_remove_flags;
+            do {
+                r = AV_RB32(buf+i);
+                t = buf[i+4] & 0x1f;
+                if (ctx->remove_nal_flags & (1<<t))
+                    needmove = 1;
+                else {
+                     if (needmove)
+                         memmove(buf + b, buf + i, r + 4);
+                    b += r + 4;
+                }
+                i += r + 4;
+            } while(i < buf_size);
+        }
+        if (needmove) {
+            memmove(buf + b, buf + i, buf_size - i);
+            buf_size -= i - b;
+            *poutbuf_size = buf_size;
+        }
+    }
+
+    if (keyframe) {
+        int i = 0;
+        uint32_t t, r, b;
+        if (ctx->bs_type == 1) {
+            while (t = find_next_nal_annexb(buf, &i, buf_size)) {
+                if (t == NAL_SPS) {
+                    b = i + 1;
+                    if (!find_next_nal_annexb(buf, &i, buf_size))
+                        break;
+                    for(i-=2;!buf[i];i--);
+                    spslen = i - b + 1;
+                    break;
+                } else if (t == NAL_SLICE || t == NAL_IDR_SLICE)
+                    break;
+            }
+        } else {
+            do {
+                r = AV_RB32(buf + i) - 1;
+                t = buf[i+4] & 0x1f;
+                if (t == NAL_SPS) {
+                    spslen = r;
+                    b = i + 5;
+                    break;
+                }
+                else if (t == NAL_SLICE || t == NAL_IDR_SLICE)
+                    break;
+                i += r + 5;
+            } while(i < buf_size);
+        }
+
+        if (spslen) {
+            r = nal_dec(spsbuf0, buf + b, spslen);
+            r = h264_modify(spsbuf1, spsbuf0, ctx, r);
+            r = nal_enc(spsbuf0, spsbuf1, r);
+            ctx->state |= 8;
+            if (spslen == r)
+                memcpy(buf + b, spsbuf0, spslen);
+            else if (r < spslen) {
+                *poutbuf_size = buf_size + r - spslen;
+                if (ctx->bs_type == 2)
+                    AV_WB32(buf + b - 5, r + 1);
+                memcpy(buf + b, spsbuf0, r);
+                memmove(buf + b + r - 1, buf + b + spslen - 1, buf_size - b - spslen);
+            } else {
+                *poutbuf = av_mallocz(buf_size + r - spslen);
+                *poutbuf_size = buf_size + r - spslen;
+                memcpy(*poutbuf, buf, b);
+                if (ctx->bs_type == 2)
+                    AV_WB32(*poutbuf + b - 5, r + 1);
+                memcpy(*poutbuf + b, spsbuf0, r);
+                memcpy(*poutbuf + b + r - 1, buf + b + spslen - 1, buf_size - b - spslen);
+                return 1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+AVBitStreamFilter ff_h264_changesps_bsf = {
+    "h264_changesps",
+    sizeof(H264SPSContext),
+    h264_changesps_filter,
+};
-- 
1.9.2.msysgit.0



More information about the ffmpeg-devel mailing list