FFmpeg
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 "mux.h"
26 #include "libavutil/avassert.h"
27 #include "libavutil/crc.h"
28 #include "libavutil/intreadwrite.h"
29 #include "libavutil/log.h"
30 #include "libavutil/mem.h"
31 #include "libavutil/opt.h"
32 #include "libavcodec/apng.h"
33 #include "libavcodec/png.h"
34 
35 typedef struct APNGMuxContext {
36  AVClass *class;
37 
38  uint32_t plays;
40 
41  uint64_t acTL_offset;
42  uint32_t frame_number;
43 
46 
48 
49  uint8_t *extra_data;
52 
53 static const uint8_t *apng_find_chunk(uint32_t tag, const uint8_t *buf,
54  size_t length)
55 {
56  size_t b;
57  for (b = 0; AV_RB32(buf + b) + 12ULL <= length - b; b += AV_RB32(buf + b) + 12ULL)
58  if (AV_RB32(&buf[b + 4]) == tag)
59  return &buf[b];
60  return NULL;
61 }
62 
63 static void apng_write_chunk(AVIOContext *io_context, uint32_t tag,
64  uint8_t *buf, size_t length)
65 {
66  const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
67  uint32_t crc = ~0U;
68  uint8_t tagbuf[4];
69 
70  av_assert0(crc_table);
71 
72  avio_wb32(io_context, length);
73  AV_WB32(tagbuf, tag);
74  crc = av_crc(crc_table, crc, tagbuf, 4);
75  avio_wb32(io_context, tag);
76  if (length > 0) {
77  crc = av_crc(crc_table, crc, buf, length);
78  avio_write(io_context, buf, length);
79  }
80  avio_wb32(io_context, ~crc);
81 }
82 
83 static int apng_write_header(AVFormatContext *format_context)
84 {
85  APNGMuxContext *apng = format_context->priv_data;
86  AVCodecParameters *par = format_context->streams[0]->codecpar;
87 
88  if (apng->last_delay.num > UINT16_MAX || apng->last_delay.den > UINT16_MAX) {
89  av_reduce(&apng->last_delay.num, &apng->last_delay.den,
90  apng->last_delay.num, apng->last_delay.den, UINT16_MAX);
91  av_log(format_context, AV_LOG_WARNING,
92  "Last frame delay is too precise. Reducing to %d/%d (%f).\n",
93  apng->last_delay.num, apng->last_delay.den, (double)apng->last_delay.num / apng->last_delay.den);
94  }
95 
96  avio_wb64(format_context->pb, PNGSIG);
97  // Remaining headers are written when they are copied from the encoder
98 
99  if (par->extradata_size) {
101  if (!apng->extra_data)
102  return AVERROR(ENOMEM);
103  apng->extra_data_size = par->extradata_size;
104  memcpy(apng->extra_data, par->extradata, par->extradata_size);
105  }
106 
107  return 0;
108 }
109 
110 static int flush_packet(AVFormatContext *format_context, AVPacket *packet)
111 {
112  APNGMuxContext *apng = format_context->priv_data;
113  AVIOContext *io_context = format_context->pb;
114  AVStream *codec_stream = format_context->streams[0];
115  uint8_t *side_data = NULL;
116  size_t side_data_size;
117 
118  av_assert0(apng->prev_packet);
119 
120  side_data = av_packet_get_side_data(apng->prev_packet, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size);
121 
122  if (side_data_size) {
123  av_freep(&apng->extra_data);
124  apng->extra_data = av_mallocz(side_data_size + AV_INPUT_BUFFER_PADDING_SIZE);
125  if (!apng->extra_data)
126  return AVERROR(ENOMEM);
127  apng->extra_data_size = side_data_size;
128  memcpy(apng->extra_data, side_data, apng->extra_data_size);
129  }
130 
131  if (apng->frame_number == 0 && !packet) {
132  const uint8_t *existing_acTL_chunk;
133  const uint8_t *existing_fcTL_chunk;
134 
135  av_log(format_context, AV_LOG_INFO, "Only a single frame so saving as a normal PNG.\n");
136 
137  // Write normal PNG headers without acTL chunk
138  existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
139  if (existing_acTL_chunk) {
140  const uint8_t *chunk_after_acTL = existing_acTL_chunk + AV_RB32(existing_acTL_chunk) + 12;
141  avio_write(io_context, apng->extra_data, existing_acTL_chunk - apng->extra_data);
142  avio_write(io_context, chunk_after_acTL, apng->extra_data + apng->extra_data_size - chunk_after_acTL);
143  } else {
144  avio_write(io_context, apng->extra_data, apng->extra_data_size);
145  }
146 
147  // Write frame data without fcTL chunk
148  existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
149  if (existing_fcTL_chunk) {
150  const uint8_t *chunk_after_fcTL = existing_fcTL_chunk + AV_RB32(existing_fcTL_chunk) + 12;
151  avio_write(io_context, apng->prev_packet->data, existing_fcTL_chunk - apng->prev_packet->data);
152  avio_write(io_context, chunk_after_fcTL, apng->prev_packet->data + apng->prev_packet->size - chunk_after_fcTL);
153  } else {
154  avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
155  }
156  } else {
157  const uint8_t *data, *data_end;
158  const uint8_t *existing_fcTL_chunk;
159 
160  if (apng->frame_number == 0) {
161  const uint8_t *existing_acTL_chunk;
162 
163  // Write normal PNG headers
164  avio_write(io_context, apng->extra_data, apng->extra_data_size);
165 
166  existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
167  if (!existing_acTL_chunk) {
168  uint8_t buf[8];
169  // Write animation control header
170  apng->acTL_offset = avio_tell(io_context);
171  AV_WB32(buf, UINT_MAX); // number of frames (filled in later)
172  AV_WB32(buf + 4, apng->plays);
173  apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
174  }
175  }
176 
177  data = apng->prev_packet->data;
178  data_end = data + apng->prev_packet->size;
179  existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
180  if (existing_fcTL_chunk) {
181  AVRational delay;
182 
183  if (AV_RB32(existing_fcTL_chunk) != APNG_FCTL_CHUNK_SIZE)
184  return AVERROR_INVALIDDATA;
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  uint8_t new_fcTL_chunk[APNG_FCTL_CHUNK_SIZE];
192 
193  if (packet) {
194  int64_t delay_num_raw = (packet->dts - apng->prev_packet->dts) * codec_stream->time_base.num;
195  int64_t delay_den_raw = codec_stream->time_base.den;
196  if (!av_reduce(&delay.num, &delay.den, delay_num_raw, delay_den_raw, UINT16_MAX) &&
197  !apng->framerate_warned) {
198  av_log(format_context, AV_LOG_WARNING,
199  "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
200  apng->framerate_warned = 1;
201  }
202  } else if (apng->last_delay.num > 0) {
203  delay = apng->last_delay;
204  } else {
205  delay = apng->prev_delay;
206  }
207 
208  avio_write(io_context, data, (existing_fcTL_chunk - 8) - data);
209  data = existing_fcTL_chunk + APNG_FCTL_CHUNK_SIZE + 4 /* CRC-32 */;
210  // Update frame control header with new delay
211  memcpy(new_fcTL_chunk, existing_fcTL_chunk, sizeof(new_fcTL_chunk));
212  AV_WB16(new_fcTL_chunk + 20, delay.num);
213  AV_WB16(new_fcTL_chunk + 22, delay.den);
214  apng_write_chunk(io_context, MKBETAG('f', 'c', 'T', 'L'),
215  new_fcTL_chunk, sizeof(new_fcTL_chunk));
216  }
217  apng->prev_delay = delay;
218  }
219 
220  // Write frame data
221  avio_write(io_context, data, data_end - data);
222  }
223  ++apng->frame_number;
224 
226  if (packet)
227  av_packet_ref(apng->prev_packet, packet);
228  return 0;
229 }
230 
231 static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
232 {
233  APNGMuxContext *apng = format_context->priv_data;
234  int ret;
235 
236  if (!apng->prev_packet) {
237  apng->prev_packet = av_packet_alloc();
238  if (!apng->prev_packet)
239  return AVERROR(ENOMEM);
240 
241  av_packet_ref(apng->prev_packet, packet);
242  } else {
243  ret = flush_packet(format_context, packet);
244  if (ret < 0)
245  return ret;
246  }
247 
248  return 0;
249 }
250 
251 static int apng_write_trailer(AVFormatContext *format_context)
252 {
253  APNGMuxContext *apng = format_context->priv_data;
254  AVIOContext *io_context = format_context->pb;
255  uint8_t buf[8];
256  int ret;
257 
258  if (apng->prev_packet) {
259  ret = flush_packet(format_context, NULL);
260  if (ret < 0)
261  return ret;
262  }
263 
264  apng_write_chunk(io_context, MKBETAG('I', 'E', 'N', 'D'), NULL, 0);
265 
266  if (apng->acTL_offset && (io_context->seekable & AVIO_SEEKABLE_NORMAL)) {
267  avio_seek(io_context, apng->acTL_offset, SEEK_SET);
268 
269  AV_WB32(buf, apng->frame_number);
270  AV_WB32(buf + 4, apng->plays);
271  apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
272  }
273 
274  return 0;
275 }
276 
278 {
279  APNGMuxContext *apng = s->priv_data;
280 
281  av_packet_free(&apng->prev_packet);
282  av_freep(&apng->extra_data);
283  apng->extra_data_size = 0;
284 }
285 
286 #define OFFSET(x) offsetof(APNGMuxContext, x)
287 #define ENC AV_OPT_FLAG_ENCODING_PARAM
288 static const AVOption options[] = {
289  { "plays", "Number of times to play the output: 0 - infinite loop, 1 - no loop", OFFSET(plays),
290  AV_OPT_TYPE_INT, { .i64 = 1 }, 0, UINT16_MAX, ENC },
291  { "final_delay", "Force delay after the last frame", OFFSET(last_delay),
292  AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, UINT16_MAX, ENC },
293  { NULL },
294 };
295 
296 static const AVClass apng_muxer_class = {
297  .class_name = "APNG muxer",
298  .item_name = av_default_item_name,
299  .version = LIBAVUTIL_VERSION_INT,
300  .option = options,
301 };
302 
304  .p.name = "apng",
305  .p.long_name = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
306  .p.mime_type = "image/png",
307  .p.extensions = "apng",
308  .priv_data_size = sizeof(APNGMuxContext),
309  .p.audio_codec = AV_CODEC_ID_NONE,
310  .p.video_codec = AV_CODEC_ID_APNG,
311  .p.subtitle_codec = AV_CODEC_ID_NONE,
312  .flags_internal = FF_OFMT_FLAG_MAX_ONE_OF_EACH |
314  .write_header = apng_write_header,
315  .write_packet = apng_write_packet,
316  .write_trailer = apng_write_trailer,
317  .deinit = apng_deinit,
318  .p.priv_class = &apng_muxer_class,
319  .p.flags = AVFMT_VARIABLE_FPS,
320 };
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:427
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:69
AVOutputFormat::name
const char * name
Definition: avformat.h:510
APNGMuxContext
Definition: apngenc.c:35
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
apng_muxer_class
static const AVClass apng_muxer_class
Definition: apngenc.c:296
apng_write_trailer
static int apng_write_trailer(AVFormatContext *format_context)
Definition: apngenc.c:251
AVCodecParameters
This struct describes the properties of an encoded stream.
Definition: codec_par.h:47
AVCRC
uint32_t AVCRC
Definition: crc.h:46
AV_PKT_DATA_NEW_EXTRADATA
@ AV_PKT_DATA_NEW_EXTRADATA
The AV_PKT_DATA_NEW_EXTRADATA is used to notify the codec or the format that the extradata buffer was...
Definition: packet.h:56
APNG_FCTL_CHUNK_SIZE
#define APNG_FCTL_CHUNK_SIZE
Definition: apng.h:42
AVFMT_VARIABLE_FPS
#define AVFMT_VARIABLE_FPS
Format allows variable fps.
Definition: avformat.h:482
APNGMuxContext::frame_number
uint32_t frame_number
Definition: apngenc.c:42
APNGMuxContext::last_delay
AVRational last_delay
Definition: apngenc.c:39
AVFormatContext::streams
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1323
AVPacket::data
uint8_t * data
Definition: packet.h:524
AVOption
AVOption.
Definition: opt.h:346
b
#define b
Definition: input.c:41
APNGMuxContext::extra_data_size
int extra_data_size
Definition: apngenc.c:50
data
const char data[16]
Definition: mxf.c:148
FF_OFMT_FLAG_ONLY_DEFAULT_CODECS
#define FF_OFMT_FLAG_ONLY_DEFAULT_CODECS
If this flag is set, then the only permitted audio/video/subtitle codec ids are AVOutputFormat....
Definition: mux.h:59
AV_CODEC_ID_APNG
@ AV_CODEC_ID_APNG
Definition: codec_id.h:265
AV_OPT_TYPE_RATIONAL
@ AV_OPT_TYPE_RATIONAL
Definition: opt.h:240
av_packet_free
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: packet.c:74
FFOutputFormat::p
AVOutputFormat p
The public AVOutputFormat.
Definition: mux.h:65
crc.h
APNGMuxContext::prev_delay
AVRational prev_delay
Definition: apngenc.c:45
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
av_reduce
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
AVRational::num
int num
Numerator.
Definition: rational.h:59
avassert.h
APNGMuxContext::prev_packet
AVPacket * prev_packet
Definition: apngenc.c:44
flush_packet
static int flush_packet(AVFormatContext *format_context, AVPacket *packet)
Definition: apngenc.c:110
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
apng_write_chunk
static void apng_write_chunk(AVIOContext *io_context, uint32_t tag, uint8_t *buf, size_t length)
Definition: apngenc.c:63
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:40
if
if(ret)
Definition: filter_design.txt:179
AVFormatContext
Format I/O context.
Definition: avformat.h:1255
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:766
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
APNGMuxContext::extra_data
uint8_t * extra_data
Definition: apngenc.c:49
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
AVStream::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avformat.h:782
NULL
#define NULL
Definition: coverity.c:32
apng.h
AV_WB16
#define AV_WB16(p, v)
Definition: intreadwrite.h:403
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1297
FFOutputFormat
Definition: mux.h:61
av_packet_ref
int av_packet_ref(AVPacket *dst, const AVPacket *src)
Setup a new reference to the data described by a given packet.
Definition: packet.c:435
AVCodecParameters::extradata_size
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:73
AV_WB32
#define AV_WB32(p, v)
Definition: intreadwrite.h:417
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
AVPacket::size
int size
Definition: packet.h:525
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:94
AVIOContext::seekable
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:261
MKBETAG
#define MKBETAG(a, b, c, d)
Definition: macros.h:56
AV_RB32
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:96
AVPacket::dts
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
Definition: packet.h:523
avio_write
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:201
avio_wb32
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:365
av_crc_get_table
const AVCRC * av_crc_get_table(AVCRCId crc_id)
Get an initialized standard CRC table.
Definition: crc.c:374
ENC
#define ENC
Definition: apngenc.c:287
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: packet.c:63
options
static const AVOption options[]
Definition: apngenc.c:288
PNGSIG
#define PNGSIG
Definition: png.h:49
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
log.h
AV_CODEC_ID_NONE
@ AV_CODEC_ID_NONE
Definition: codec_id.h:50
OFFSET
#define OFFSET(x)
Definition: apngenc.c:286
av_packet_get_side_data
uint8_t * av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type, size_t *size)
Get side information from packet.
Definition: packet.c:252
APNGMuxContext::framerate_warned
int framerate_warned
Definition: apngenc.c:47
FF_OFMT_FLAG_MAX_ONE_OF_EACH
#define FF_OFMT_FLAG_MAX_ONE_OF_EACH
If this flag is set, it indicates that for each codec type whose corresponding default codec (i....
Definition: mux.h:50
apng_find_chunk
static const uint8_t * apng_find_chunk(uint32_t tag, const uint8_t *buf, size_t length)
Definition: apngenc.c:53
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
tag
uint32_t tag
Definition: movenc.c:1787
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:743
apng_write_packet
static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
Definition: apngenc.c:231
avio_seek
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:231
AVClass::class_name
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:71
avformat.h
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: defs.h:40
U
#define U(x)
Definition: vpx_arith.h:37
ff_apng_muxer
const FFOutputFormat ff_apng_muxer
Definition: apngenc.c:303
AVIO_SEEKABLE_NORMAL
#define AVIO_SEEKABLE_NORMAL
Seeking works like for a local file.
Definition: avio.h:41
av_crc
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:392
AVRational::den
int den
Denominator.
Definition: rational.h:60
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:235
avio_wb64
void avio_wb64(AVIOContext *s, uint64_t val)
Definition: aviobuf.c:431
AV_CRC_32_IEEE_LE
@ AV_CRC_32_IEEE_LE
Definition: crc.h:53
APNGMuxContext::acTL_offset
uint64_t acTL_offset
Definition: apngenc.c:41
mem.h
APNGMuxContext::plays
uint32_t plays
Definition: apngenc.c:38
AVPacket
This structure stores compressed data.
Definition: packet.h:501
png.h
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
apng_write_header
static int apng_write_header(AVFormatContext *format_context)
Definition: apngenc.c:83
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1283
AV_RB16
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:98
apng_deinit
static void apng_deinit(AVFormatContext *s)
Definition: apngenc.c:277
mux.h