FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
apngenc.c
Go to the documentation of this file.
1 /*
2  * APNG muxer
3  * Copyright (c) 2015 Donny Yang
4  *
5  * first version by Donny Yang <work@kota.moe>
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 #include "avformat.h"
25 #include "internal.h"
26 #include "libavutil/avassert.h"
27 #include "libavutil/crc.h"
28 #include "libavutil/intreadwrite.h"
29 #include "libavutil/log.h"
30 #include "libavutil/opt.h"
31 #include "libavcodec/png.h"
32 #include "libavcodec/apng.h"
33 
34 typedef struct APNGMuxContext {
35  AVClass *class;
36 
37  uint32_t plays;
39 
40  uint64_t acTL_offset;
41  uint32_t frame_number;
42 
45 
47 
51 
52 static uint8_t *apng_find_chunk(uint32_t tag, uint8_t *buf, size_t length)
53 {
54  size_t b;
55  for (b = 0; b < length; b += AV_RB32(buf + b) + 12)
56  if (AV_RB32(&buf[b + 4]) == tag)
57  return &buf[b];
58  return NULL;
59 }
60 
61 static void apng_write_chunk(AVIOContext *io_context, uint32_t tag,
62  uint8_t *buf, size_t length)
63 {
64  const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
65  uint32_t crc = ~0U;
66  uint8_t tagbuf[4];
67 
68  av_assert0(crc_table);
69 
70  avio_wb32(io_context, length);
71  AV_WB32(tagbuf, tag);
72  crc = av_crc(crc_table, crc, tagbuf, 4);
73  avio_wb32(io_context, tag);
74  if (length > 0) {
75  crc = av_crc(crc_table, crc, buf, length);
76  avio_write(io_context, buf, length);
77  }
78  avio_wb32(io_context, ~crc);
79 }
80 
81 static int apng_write_header(AVFormatContext *format_context)
82 {
83  APNGMuxContext *apng = format_context->priv_data;
84  AVCodecParameters *par = format_context->streams[0]->codecpar;
85 
86  if (format_context->nb_streams != 1 ||
87  format_context->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
88  format_context->streams[0]->codecpar->codec_id != AV_CODEC_ID_APNG) {
89  av_log(format_context, AV_LOG_ERROR,
90  "APNG muxer supports only a single video APNG stream.\n");
91  return AVERROR(EINVAL);
92  }
93 
94  if (apng->last_delay.num > USHRT_MAX || apng->last_delay.den > USHRT_MAX) {
95  av_reduce(&apng->last_delay.num, &apng->last_delay.den,
96  apng->last_delay.num, apng->last_delay.den, USHRT_MAX);
97  av_log(format_context, AV_LOG_WARNING,
98  "Last frame delay is too precise. Reducing to %d/%d (%f).\n",
99  apng->last_delay.num, apng->last_delay.den, (double)apng->last_delay.num / apng->last_delay.den);
100  }
101 
102  avio_wb64(format_context->pb, PNGSIG);
103  // Remaining headers are written when they are copied from the encoder
104 
105  if (par->extradata_size) {
107  if (!apng->extra_data)
108  return AVERROR(ENOMEM);
109  apng->extra_data_size = par->extradata_size;
110  memcpy(apng->extra_data, par->extradata, par->extradata_size);
111  }
112 
113  return 0;
114 }
115 
116 static int flush_packet(AVFormatContext *format_context, AVPacket *packet)
117 {
118  APNGMuxContext *apng = format_context->priv_data;
119  AVIOContext *io_context = format_context->pb;
120  AVStream *codec_stream = format_context->streams[0];
121  uint8_t *side_data = NULL;
122  int side_data_size = 0;
123 
124  av_assert0(apng->prev_packet);
125 
126  side_data = av_packet_get_side_data(apng->prev_packet, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size);
127 
128  if (side_data_size) {
129  av_freep(&apng->extra_data);
130  apng->extra_data = av_mallocz(side_data_size + AV_INPUT_BUFFER_PADDING_SIZE);
131  if (!apng->extra_data)
132  return AVERROR(ENOMEM);
133  apng->extra_data_size = side_data_size;
134  memcpy(apng->extra_data, side_data, apng->extra_data_size);
135  }
136 
137  if (apng->frame_number == 0 && !packet) {
138  uint8_t *existing_acTL_chunk;
139  uint8_t *existing_fcTL_chunk;
140 
141  av_log(format_context, AV_LOG_INFO, "Only a single frame so saving as a normal PNG.\n");
142 
143  // Write normal PNG headers without acTL chunk
144  existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
145  if (existing_acTL_chunk) {
146  uint8_t *chunk_after_acTL = existing_acTL_chunk + AV_RB32(existing_acTL_chunk) + 12;
147  avio_write(io_context, apng->extra_data, existing_acTL_chunk - apng->extra_data);
148  avio_write(io_context, chunk_after_acTL, apng->extra_data + apng->extra_data_size - chunk_after_acTL);
149  } else {
150  avio_write(io_context, apng->extra_data, apng->extra_data_size);
151  }
152 
153  // Write frame data without fcTL chunk
154  existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
155  if (existing_fcTL_chunk) {
156  uint8_t *chunk_after_fcTL = existing_fcTL_chunk + AV_RB32(existing_fcTL_chunk) + 12;
157  avio_write(io_context, apng->prev_packet->data, existing_fcTL_chunk - apng->prev_packet->data);
158  avio_write(io_context, chunk_after_fcTL, apng->prev_packet->data + apng->prev_packet->size - chunk_after_fcTL);
159  } else {
160  avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
161  }
162  } else {
163  uint8_t *existing_fcTL_chunk;
164 
165  if (apng->frame_number == 0) {
166  uint8_t *existing_acTL_chunk;
167 
168  // Write normal PNG headers
169  avio_write(io_context, apng->extra_data, apng->extra_data_size);
170 
171  existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
172  if (!existing_acTL_chunk) {
173  uint8_t buf[8];
174  // Write animation control header
175  apng->acTL_offset = avio_tell(io_context);
176  AV_WB32(buf, UINT_MAX); // number of frames (filled in later)
177  AV_WB32(buf + 4, apng->plays);
178  apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
179  }
180  }
181 
182  existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
183  if (existing_fcTL_chunk) {
184  AVRational delay;
185 
186  existing_fcTL_chunk += 8;
187  delay.num = AV_RB16(existing_fcTL_chunk + 20);
188  delay.den = AV_RB16(existing_fcTL_chunk + 22);
189 
190  if (delay.num == 0 && delay.den == 0) {
191  if (packet) {
192  int64_t delay_num_raw = (packet->dts - apng->prev_packet->dts) * codec_stream->time_base.num;
193  int64_t delay_den_raw = codec_stream->time_base.den;
194  if (!av_reduce(&delay.num, &delay.den, delay_num_raw, delay_den_raw, USHRT_MAX) &&
195  !apng->framerate_warned) {
196  av_log(format_context, AV_LOG_WARNING,
197  "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
198  apng->framerate_warned = 1;
199  }
200  } else if (apng->last_delay.num > 0) {
201  delay = apng->last_delay;
202  } else {
203  delay = apng->prev_delay;
204  }
205 
206  // Update frame control header with new delay
207  AV_WB16(existing_fcTL_chunk + 20, delay.num);
208  AV_WB16(existing_fcTL_chunk + 22, delay.den);
209  AV_WB32(existing_fcTL_chunk + 26, ~av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), ~0U, existing_fcTL_chunk - 4, 26 + 4));
210  }
211  apng->prev_delay = delay;
212  }
213 
214  // Write frame data
215  avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
216  }
217  ++apng->frame_number;
218 
220  if (packet)
221  av_packet_ref(apng->prev_packet, packet);
222  return 0;
223 }
224 
225 static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
226 {
227  APNGMuxContext *apng = format_context->priv_data;
228  int ret;
229 
230  if (!apng->prev_packet) {
231  apng->prev_packet = av_packet_alloc();
232  if (!apng->prev_packet)
233  return AVERROR(ENOMEM);
234 
235  av_packet_ref(apng->prev_packet, packet);
236  } else {
237  ret = flush_packet(format_context, packet);
238  if (ret < 0)
239  return ret;
240  }
241 
242  return 0;
243 }
244 
245 static int apng_write_trailer(AVFormatContext *format_context)
246 {
247  APNGMuxContext *apng = format_context->priv_data;
248  AVIOContext *io_context = format_context->pb;
249  uint8_t buf[8];
250  int ret;
251 
252  if (apng->prev_packet) {
253  ret = flush_packet(format_context, NULL);
254  av_freep(&apng->prev_packet);
255  if (ret < 0)
256  return ret;
257  }
258 
259  apng_write_chunk(io_context, MKBETAG('I', 'E', 'N', 'D'), NULL, 0);
260 
261  if (apng->acTL_offset && (io_context->seekable & AVIO_SEEKABLE_NORMAL)) {
262  avio_seek(io_context, apng->acTL_offset, SEEK_SET);
263 
264  AV_WB32(buf, apng->frame_number);
265  AV_WB32(buf + 4, apng->plays);
266  apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
267  }
268 
269  av_freep(&apng->extra_data);
270  apng->extra_data = 0;
271 
272  return 0;
273 }
274 
275 #define OFFSET(x) offsetof(APNGMuxContext, x)
276 #define ENC AV_OPT_FLAG_ENCODING_PARAM
277 static const AVOption options[] = {
278  { "plays", "Number of times to play the output: 0 - infinite loop, 1 - no loop", OFFSET(plays),
279  AV_OPT_TYPE_INT, { .i64 = 1 }, 0, UINT_MAX, ENC },
280  { "final_delay", "Force delay after the last frame", OFFSET(last_delay),
281  AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, USHRT_MAX, ENC },
282  { NULL },
283 };
284 
285 static const AVClass apng_muxer_class = {
286  .class_name = "APNG muxer",
287  .item_name = av_default_item_name,
288  .version = LIBAVUTIL_VERSION_INT,
289  .option = options,
290 };
291 
293  .name = "apng",
294  .long_name = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
295  .mime_type = "image/png",
296  .extensions = "apng",
297  .priv_data_size = sizeof(APNGMuxContext),
298  .audio_codec = AV_CODEC_ID_NONE,
299  .video_codec = AV_CODEC_ID_APNG,
303  .priv_class = &apng_muxer_class,
305 };
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:671
void avio_wb64(AVIOContext *s, uint64_t val)
Definition: aviobuf.c:468
static int apng_write_trailer(AVFormatContext *format_context)
Definition: apngenc.c:245
#define NULL
Definition: coverity.c:32
Bytestream IO Context.
Definition: avio.h:161
AVOption.
Definition: opt.h:246
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
#define LIBAVUTIL_VERSION_INT
Definition: version.h:86
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:4152
int num
Numerator.
Definition: rational.h:59
static const AVClass apng_muxer_class
Definition: apngenc.c:285
int size
Definition: avcodec.h:1680
const char * b
Definition: vf_curves.c:113
int framerate_warned
Definition: apngenc.c:46
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:244
uint64_t acTL_offset
Definition: apngenc.c:40
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:222
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:87
This struct describes the properties of an encoded stream.
Definition: avcodec.h:4144
Format I/O context.
Definition: avformat.h:1349
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
uint8_t
AVOptions.
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:87
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1417
Public header for CRC hash function implementation.
static int flush_packet(AVFormatContext *format_context, AVPacket *packet)
Definition: apngenc.c:116
uint8_t * data
Definition: avcodec.h:1679
static int flags
Definition: log.c:57
uint32_t tag
Definition: movenc.c:1409
static void apng_write_chunk(AVIOContext *io_context, uint32_t tag, uint8_t *buf, size_t length)
Definition: apngenc.c:61
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:556
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
Definition: rational.c:35
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:216
#define AV_WB16(p, v)
Definition: intreadwrite.h:410
#define av_log(a,...)
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
Definition: avpacket.c:627
uint8_t * extra_data
Definition: apngenc.c:48
#define U(x)
Definition: vp56_arith.h:37
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
av_default_item_name
#define AVERROR(e)
Definition: error.h:43
uint8_t * av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type, int *size)
Get side information from packet.
Definition: avpacket.c:350
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:179
AVOutputFormat ff_apng_muxer
Definition: apngenc.c:292
AVPacket * prev_packet
Definition: apngenc.c:43
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:4148
#define PNGSIG
Definition: png.h:47
simple assert() macros that are a bit more flexible than ISO C assert().
GLsizei GLsizei * length
Definition: opengl_enc.c:115
AVRational prev_delay
Definition: apngenc.c:44
int extradata_size
Size of the extradata content in bytes.
Definition: avcodec.h:4170
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1405
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:261
AVRational last_delay
Definition: apngenc.c:38
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:94
const char * name
Definition: avformat.h:524
uint32_t av_crc(const AVCRC *ctx, uint32_t crc, const uint8_t *buffer, size_t length)
Calculate the CRC of a block.
Definition: crc.c:357
static uint8_t * apng_find_chunk(uint32_t tag, uint8_t *buf, size_t length)
Definition: apngenc.c:52
#define ENC
Definition: apngenc.c:276
Stream structure.
Definition: avformat.h:889
#define AVIO_SEEKABLE_NORMAL
Seeking works like for a local file.
Definition: avio.h:40
The AV_PKT_DATA_NEW_EXTRADATA is used to notify the codec or the format that the extradata buffer was...
Definition: avcodec.h:1420
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
#define OFFSET(x)
Definition: apngenc.c:275
AVIOContext * pb
I/O context.
Definition: avformat.h:1391
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:618
void * buf
Definition: avisynth_c.h:690
Describe the class of an AVClass context structure.
Definition: log.h:67
#define AV_WB32(p, v)
Definition: intreadwrite.h:424
static const AVOption options[]
Definition: apngenc.c:277
Rational number (pair of numerator and denominator).
Definition: rational.h:58
uint32_t frame_number
Definition: apngenc.c:41
static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
Definition: apngenc.c:225
int extra_data_size
Definition: apngenc.c:49
const AVCRC * av_crc_get_table(AVCRCId crc_id)
Get an initialized standard CRC table.
Definition: crc.c:343
Main libavformat public API header.
uint32_t plays
Definition: apngenc.c:37
if(ret< 0)
Definition: vf_mcdeint.c:279
int den
Denominator.
Definition: rational.h:60
#define MKBETAG(a, b, c, d)
Definition: common.h:343
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
Definition: avcodec.h:777
#define AVFMT_VARIABLE_FPS
Format allows variable fps.
Definition: avformat.h:489
void * priv_data
Format private data.
Definition: avformat.h:1377
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: avpacket.c:51
APNG common header.
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:337
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:4166
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: avcodec.h:1678
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:382
#define av_freep(p)
AVCodecParameters * codecpar
Definition: avformat.h:1252
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:926
This structure stores compressed data.
Definition: avcodec.h:1656
uint32_t AVCRC
Definition: crc.h:47
static int apng_write_header(AVFormatContext *format_context)
Definition: apngenc.c:81