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 
48 
49 static uint8_t *apng_find_chunk(uint32_t tag, uint8_t *buf, size_t length)
50 {
51  size_t b;
52  for (b = 0; b < length; b += AV_RB32(buf + b) + 12)
53  if (AV_RB32(&buf[b + 4]) == tag)
54  return &buf[b];
55  return NULL;
56 }
57 
58 static void apng_write_chunk(AVIOContext *io_context, uint32_t tag,
59  uint8_t *buf, size_t length)
60 {
61  const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
62  uint32_t crc = ~0U;
63  uint8_t tagbuf[4];
64 
65  av_assert0(crc_table);
66 
67  avio_wb32(io_context, length);
68  AV_WB32(tagbuf, tag);
69  crc = av_crc(crc_table, crc, tagbuf, 4);
70  avio_wb32(io_context, tag);
71  if (length > 0) {
72  crc = av_crc(crc_table, crc, buf, length);
73  avio_write(io_context, buf, length);
74  }
75  avio_wb32(io_context, ~crc);
76 }
77 
78 static int apng_write_header(AVFormatContext *format_context)
79 {
80  APNGMuxContext *apng = format_context->priv_data;
81 
82  if (format_context->nb_streams != 1 ||
83  format_context->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
84  format_context->streams[0]->codecpar->codec_id != AV_CODEC_ID_APNG) {
85  av_log(format_context, AV_LOG_ERROR,
86  "APNG muxer supports only a single video APNG stream.\n");
87  return AVERROR(EINVAL);
88  }
89 
90  if (apng->last_delay.num > USHRT_MAX || apng->last_delay.den > USHRT_MAX) {
91  av_reduce(&apng->last_delay.num, &apng->last_delay.den,
92  apng->last_delay.num, apng->last_delay.den, USHRT_MAX);
93  av_log(format_context, AV_LOG_WARNING,
94  "Last frame delay is too precise. Reducing to %d/%d (%f).\n",
95  apng->last_delay.num, apng->last_delay.den, (double)apng->last_delay.num / apng->last_delay.den);
96  }
97 
98  avio_wb64(format_context->pb, PNGSIG);
99  // Remaining headers are written when they are copied from the encoder
100 
101  return 0;
102 }
103 
104 static void flush_packet(AVFormatContext *format_context, AVPacket *packet)
105 {
106  APNGMuxContext *apng = format_context->priv_data;
107  AVIOContext *io_context = format_context->pb;
108  AVStream *codec_stream = format_context->streams[0];
109  AVCodecParameters *codec_par = codec_stream->codecpar;
110 
111  av_assert0(apng->prev_packet);
112 
113  if (apng->frame_number == 0 && !packet) {
114  uint8_t *existing_acTL_chunk;
115  uint8_t *existing_fcTL_chunk;
116 
117  av_log(format_context, AV_LOG_INFO, "Only a single frame so saving as a normal PNG.\n");
118 
119  // Write normal PNG headers without acTL chunk
120  existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), codec_par->extradata, codec_par->extradata_size);
121  if (existing_acTL_chunk) {
122  uint8_t *chunk_after_acTL = existing_acTL_chunk + AV_RB32(existing_acTL_chunk) + 12;
123  avio_write(io_context, codec_par->extradata, existing_acTL_chunk - codec_par->extradata);
124  avio_write(io_context, chunk_after_acTL, codec_par->extradata + codec_par->extradata_size - chunk_after_acTL);
125  } else {
126  avio_write(io_context, codec_par->extradata, codec_par->extradata_size);
127  }
128 
129  // Write frame data without fcTL chunk
130  existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
131  if (existing_fcTL_chunk) {
132  uint8_t *chunk_after_fcTL = existing_fcTL_chunk + AV_RB32(existing_fcTL_chunk) + 12;
133  avio_write(io_context, apng->prev_packet->data, existing_fcTL_chunk - apng->prev_packet->data);
134  avio_write(io_context, chunk_after_fcTL, apng->prev_packet->data + apng->prev_packet->size - chunk_after_fcTL);
135  } else {
136  avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
137  }
138  } else {
139  uint8_t *existing_fcTL_chunk;
140 
141  if (apng->frame_number == 0) {
142  uint8_t *existing_acTL_chunk;
143 
144  // Write normal PNG headers
145  avio_write(io_context, codec_par->extradata, codec_par->extradata_size);
146 
147  existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), codec_par->extradata, codec_par->extradata_size);
148  if (!existing_acTL_chunk) {
149  uint8_t buf[8];
150  // Write animation control header
151  apng->acTL_offset = avio_tell(io_context);
152  AV_WB32(buf, UINT_MAX); // number of frames (filled in later)
153  AV_WB32(buf + 4, apng->plays);
154  apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
155  }
156  }
157 
158  existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
159  if (existing_fcTL_chunk) {
160  AVRational delay;
161 
162  existing_fcTL_chunk += 8;
163  delay.num = AV_RB16(existing_fcTL_chunk + 20);
164  delay.den = AV_RB16(existing_fcTL_chunk + 22);
165 
166  if (delay.num == 0 && delay.den == 0) {
167  if (packet) {
168  int64_t delay_num_raw = (packet->dts - apng->prev_packet->dts) * codec_stream->time_base.num;
169  int64_t delay_den_raw = codec_stream->time_base.den;
170  if (!av_reduce(&delay.num, &delay.den, delay_num_raw, delay_den_raw, USHRT_MAX) &&
171  !apng->framerate_warned) {
172  av_log(format_context, AV_LOG_WARNING,
173  "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
174  apng->framerate_warned = 1;
175  }
176  } else if (apng->last_delay.num > 0) {
177  delay = apng->last_delay;
178  } else {
179  delay = apng->prev_delay;
180  }
181 
182  // Update frame control header with new delay
183  AV_WB16(existing_fcTL_chunk + 20, delay.num);
184  AV_WB16(existing_fcTL_chunk + 22, delay.den);
185  AV_WB32(existing_fcTL_chunk + 26, ~av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), ~0U, existing_fcTL_chunk - 4, 26 + 4));
186  }
187  apng->prev_delay = delay;
188  }
189 
190  // Write frame data
191  avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
192  }
193  ++apng->frame_number;
194 
196  if (packet)
197  av_copy_packet(apng->prev_packet, packet);
198 }
199 
200 static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
201 {
202  APNGMuxContext *apng = format_context->priv_data;
203 
204  if (!apng->prev_packet) {
205  apng->prev_packet = av_malloc(sizeof(*apng->prev_packet));
206  if (!apng->prev_packet)
207  return AVERROR(ENOMEM);
208 
209  av_copy_packet(apng->prev_packet, packet);
210  } else {
211  flush_packet(format_context, packet);
212  }
213 
214  return 0;
215 }
216 
217 static int apng_write_trailer(AVFormatContext *format_context)
218 {
219  APNGMuxContext *apng = format_context->priv_data;
220  AVIOContext *io_context = format_context->pb;
221  uint8_t buf[8];
222 
223  if (apng->prev_packet) {
224  flush_packet(format_context, NULL);
225  av_freep(&apng->prev_packet);
226  }
227 
228  apng_write_chunk(io_context, MKBETAG('I', 'E', 'N', 'D'), NULL, 0);
229 
230  if (apng->acTL_offset && io_context->seekable) {
231  avio_seek(io_context, apng->acTL_offset, SEEK_SET);
232 
233  AV_WB32(buf, apng->frame_number);
234  AV_WB32(buf + 4, apng->plays);
235  apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
236  }
237 
238  return 0;
239 }
240 
241 #define OFFSET(x) offsetof(APNGMuxContext, x)
242 #define ENC AV_OPT_FLAG_ENCODING_PARAM
243 static const AVOption options[] = {
244  { "plays", "Number of times to play the output: 0 - infinite loop, 1 - no loop", OFFSET(plays),
245  AV_OPT_TYPE_INT, { .i64 = 1 }, 0, UINT_MAX, ENC },
246  { "final_delay", "Force delay after the last frame", OFFSET(last_delay),
247  AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, USHRT_MAX, ENC },
248  { NULL },
249 };
250 
251 static const AVClass apng_muxer_class = {
252  .class_name = "APNG muxer",
253  .item_name = av_default_item_name,
254  .version = LIBAVUTIL_VERSION_INT,
255  .option = options,
256 };
257 
259  .name = "apng",
260  .long_name = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
261  .mime_type = "image/png",
262  .extensions = "apng",
263  .priv_data_size = sizeof(APNGMuxContext),
264  .audio_codec = AV_CODEC_ID_NONE,
265  .video_codec = AV_CODEC_ID_APNG,
269  .priv_class = &apng_muxer_class,
271 };
void avio_wb64(AVIOContext *s, uint64_t val)
Definition: aviobuf.c:440
static int apng_write_trailer(AVFormatContext *format_context)
Definition: apngenc.c:217
#define NULL
Definition: coverity.c:32
Bytestream IO Context.
Definition: avio.h:147
AVOption.
Definition: opt.h:245
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3980
int num
Numerator.
Definition: rational.h:59
static const AVClass apng_muxer_class
Definition: apngenc.c:251
int size
Definition: avcodec.h:1602
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:230
uint64_t acTL_offset
Definition: apngenc.c:40
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:3972
Format I/O context.
Definition: avformat.h:1338
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
#define av_malloc(s)
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:1406
Public header for CRC hash function implementation.
uint8_t * data
Definition: avcodec.h:1601
uint32_t tag
Definition: movenc.c:1382
static void apng_write_chunk(AVIOContext *io_context, uint32_t tag, uint8_t *buf, size_t length)
Definition: apngenc.c:58
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:511
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:204
#define AV_WB16(p, v)
Definition: intreadwrite.h:405
#define av_log(a,...)
#define U(x)
Definition: vp56_arith.h:37
static void flush_packet(AVFormatContext *format_context, AVPacket *packet)
Definition: apngenc.c:104
#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
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:176
AVOutputFormat ff_apng_muxer
Definition: apngenc.c:258
AVPacket * prev_packet
Definition: apngenc.c:43
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3976
#define PNGSIG
Definition: png.h:52
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:3998
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1394
int seekable
A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable.
Definition: avio.h:243
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:49
#define ENC
Definition: apngenc.c:242
Stream structure.
Definition: avformat.h:889
#define AV_LOG_INFO
Standard information.
Definition: log.h:187
#define OFFSET(x)
Definition: apngenc.c:241
AVIOContext * pb
I/O context.
Definition: avformat.h:1380
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:567
int av_copy_packet(AVPacket *dst, const AVPacket *src)
Copy packet, including contents.
Definition: avpacket.c:264
void * buf
Definition: avisynth_c.h:690
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost)
Definition: ffmpeg.c:645
Describe the class of an AVClass context structure.
Definition: log.h:67
#define AV_WB32(p, v)
Definition: intreadwrite.h:419
static const AVOption options[]
Definition: apngenc.c:243
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:200
static int flags
Definition: cpu.c:47
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:282
int den
Denominator.
Definition: rational.h:60
#define MKBETAG(a, b, c, d)
Definition: common.h:343
#define AVFMT_VARIABLE_FPS
Format allows variable fps.
Definition: avformat.h:489
void * priv_data
Format private data.
Definition: avformat.h:1366
APNG common header.
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:344
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:3994
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: avcodec.h:1600
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:354
#define av_freep(p)
AVCodecParameters * codecpar
Definition: avformat.h:1241
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:1578
uint32_t AVCRC
Definition: crc.h:47
static int apng_write_header(AVFormatContext *format_context)
Definition: apngenc.c:78