⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gif.c

📁 ffmpeg的完整源代码和作者自己写的文档。不但有在Linux的工程哦
💻 C
📖 第 1 页 / 共 2 页
字号:
                                         (three bytes of data to follow)
                byte  16       : 1 (hex 0x01)
                bytes 17 to 18 : 0 to 65535, an unsigned integer in
                                         lo-hi byte format. This indicate the
                                         number of iterations the loop should
                                         be executed.
                bytes 19       : 0 (hex 0x00) a Data Sub-block Terminator
        */

    /* application extension header */
#ifdef GIF_ADD_APP_HEADER
    if (loop_count >= 0 && loop_count <= 65535) {
    put_byte(pb, 0x21);
    put_byte(pb, 0xff);
    put_byte(pb, 0x0b);
        put_tag(pb, "NETSCAPE2.0");  // bytes 4 to 14
        put_byte(pb, 0x03); // byte 15
        put_byte(pb, 0x01); // byte 16
        put_le16(pb, (uint16_t)loop_count);
        put_byte(pb, 0x00); // byte 19
    }
#endif
    return 0;
}

/* this is maybe slow, but allows for extensions */
static inline unsigned char gif_clut_index(uint8_t r, uint8_t g, uint8_t b)
{
    return ((((r)/47)%6)*6*6+(((g)/47)%6)*6+(((b)/47)%6));
}


static int gif_image_write_image(ByteIOContext *pb,
                                 int x1, int y1, int width, int height,
                                 const uint8_t *buf, int linesize, int pix_fmt)
{
    PutBitContext p;
    uint8_t buffer[200]; /* 100 * 9 / 8 = 113 */
    int i, left, w, v;
    const uint8_t *ptr;
    /* image block */

    put_byte(pb, 0x2c);
    put_le16(pb, x1);
    put_le16(pb, y1);
    put_le16(pb, width);
    put_le16(pb, height);
    put_byte(pb, 0x00); /* flags */
    /* no local clut */

    put_byte(pb, 0x08);

    left= width * height;

    init_put_bits(&p, buffer, 130);

/*
 * the thing here is the bitstream is written as little packets, with a size byte before
 * but it's still the same bitstream between packets (no flush !)
 */
    ptr = buf;
    w = width;
    while(left>0) {

        gif_put_bits_rev(&p, 9, 0x0100); /* clear code */

        for(i=(left<GIF_CHUNKS)?left:GIF_CHUNKS;i;i--) {
            if (pix_fmt == PIX_FMT_RGB24) {
                v = gif_clut_index(ptr[0], ptr[1], ptr[2]);
                ptr+=3;
            } else {
                v = *ptr++;
            }
            gif_put_bits_rev(&p, 9, v);
            if (--w == 0) {
                w = width;
                buf += linesize;
                ptr = buf;
            }
        }

        if(left<=GIF_CHUNKS) {
            gif_put_bits_rev(&p, 9, 0x101); /* end of stream */
            gif_flush_put_bits_rev(&p);
        }
        if(pbBufPtr(&p) - p.buf > 0) {
            put_byte(pb, pbBufPtr(&p) - p.buf); /* byte count of the packet */
            put_buffer(pb, p.buf, pbBufPtr(&p) - p.buf); /* the actual buffer */
            p.buf_ptr = p.buf; /* dequeue the bytes off the bitstream */
        }
        left-=GIF_CHUNKS;
    }
    put_byte(pb, 0x00); /* end of image block */

    return 0;
}

typedef struct {
    int64_t time, file_time;
    uint8_t buffer[100]; /* data chunks */
} GIFContext;

static int gif_write_header(AVFormatContext *s)
{
    GIFContext *gif = s->priv_data;
    ByteIOContext *pb = &s->pb;
    AVCodecContext *enc, *video_enc;
    int i, width, height, loop_count /*, rate*/;

/* XXX: do we reject audio streams or just ignore them ?
    if(s->nb_streams > 1)
        return -1;
*/
    gif->time = 0;
    gif->file_time = 0;

    video_enc = NULL;
    for(i=0;i<s->nb_streams;i++) {
        enc = s->streams[i]->codec;
        if (enc->codec_type != CODEC_TYPE_AUDIO)
            video_enc = enc;
    }

    if (!video_enc) {
        av_free(gif);
        return -1;
    } else {
        width = video_enc->width;
        height = video_enc->height;
        loop_count = s->loop_output;
//        rate = video_enc->time_base.den;
    }

    if (video_enc->pix_fmt != PIX_FMT_RGB24) {
        av_log(s, AV_LOG_ERROR, "ERROR: gif only handles the rgb24 pixel format. Use -pix_fmt rgb24.\n");
        return AVERROR(EIO);
    }

    gif_image_write_header(pb, width, height, loop_count, NULL);

    put_flush_packet(&s->pb);
    return 0;
}

static int gif_write_video(AVFormatContext *s,
                           AVCodecContext *enc, const uint8_t *buf, int size)
{
    ByteIOContext *pb = &s->pb;
    GIFContext *gif = s->priv_data;
    int jiffies;
    int64_t delay;

    /* graphic control extension block */
    put_byte(pb, 0x21);
    put_byte(pb, 0xf9);
    put_byte(pb, 0x04); /* block size */
    put_byte(pb, 0x04); /* flags */

    /* 1 jiffy is 1/70 s */
    /* the delay_time field indicates the number of jiffies - 1 */
    delay = gif->file_time - gif->time;

    /* XXX: should use delay, in order to be more accurate */
    /* instead of using the same rounded value each time */
    /* XXX: don't even remember if I really use it for now */
    jiffies = (70*enc->time_base.num/enc->time_base.den) - 1;

    put_le16(pb, jiffies);

    put_byte(pb, 0x1f); /* transparent color index */
    put_byte(pb, 0x00);

    gif_image_write_image(pb, 0, 0, enc->width, enc->height,
                          buf, enc->width * 3, PIX_FMT_RGB24);

    put_flush_packet(&s->pb);
    return 0;
}

static int gif_write_packet(AVFormatContext *s, AVPacket *pkt)
{
    AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
    if (codec->codec_type == CODEC_TYPE_AUDIO)
        return 0; /* just ignore audio */
    else
        return gif_write_video(s, codec, pkt->data, pkt->size);
}

static int gif_write_trailer(AVFormatContext *s)
{
    ByteIOContext *pb = &s->pb;

    put_byte(pb, 0x3b);
    put_flush_packet(&s->pb);
    return 0;
}

AVOutputFormat gif_muxer = {
    "gif",
    "GIF Animation",
    "image/gif",
    "gif",
    sizeof(GIFContext),
    CODEC_ID_NONE,
    CODEC_ID_RAWVIDEO,
    gif_write_header,
    gif_write_packet,
    gif_write_trailer,
};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -