📄 gif.c
字号:
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=0;i<GIF_CHUNKS;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 */ } if(left<=GIF_CHUNKS) { put_byte(pb, 0x00); /* end of image block */ } left-=GIF_CHUNKS; } 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/*, 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;// rate = video_enc->frame_rate; } /* XXX: is it allowed ? seems to work so far... */ video_enc->pix_fmt = PIX_FMT_RGB24; gif_image_write_header(pb, width, height, 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->frame_rate_base/enc->frame_rate) - 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;}/* better than nothing gif image writer */int gif_write(ByteIOContext *pb, AVImageInfo *info){ gif_image_write_header(pb, info->width, info->height, (uint32_t *)info->pict.data[1]); gif_image_write_image(pb, 0, 0, info->width, info->height, info->pict.data[0], info->pict.linesize[0], PIX_FMT_PAL8); put_byte(pb, 0x3b); put_flush_packet(pb); return 0;}static AVOutputFormat gif_oformat = { "gif", "GIF Animation", "image/gif", "gif", sizeof(GIFContext), CODEC_ID_NONE, CODEC_ID_RAWVIDEO, gif_write_header, gif_write_packet, gif_write_trailer,};extern AVInputFormat gif_iformat;int gif_init(void){ av_register_output_format(&gif_oformat); av_register_input_format(&gif_iformat); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -