]> git.sesse.net Git - ffmpeg/blob - libavformat/apngenc.c
Merge commit '61bd0ed781b56eea1e8e851aab34a2ee3b59fbac'
[ffmpeg] / libavformat / apngenc.c
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;
38     AVRational last_delay;
39
40     uint64_t acTL_offset;
41     uint32_t frame_number;
42
43     AVPacket *prev_packet;
44     AVRational prev_delay;
45
46     int framerate_warned;
47
48     uint8_t *extra_data;
49     int extra_data_size;
50 } APNGMuxContext;
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
85     if (format_context->nb_streams != 1 ||
86         format_context->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
87         format_context->streams[0]->codecpar->codec_id   != AV_CODEC_ID_APNG) {
88         av_log(format_context, AV_LOG_ERROR,
89                "APNG muxer supports only a single video APNG stream.\n");
90         return AVERROR(EINVAL);
91     }
92
93     if (apng->last_delay.num > USHRT_MAX || apng->last_delay.den > USHRT_MAX) {
94         av_reduce(&apng->last_delay.num, &apng->last_delay.den,
95                   apng->last_delay.num, apng->last_delay.den, USHRT_MAX);
96         av_log(format_context, AV_LOG_WARNING,
97                "Last frame delay is too precise. Reducing to %d/%d (%f).\n",
98                apng->last_delay.num, apng->last_delay.den, (double)apng->last_delay.num / apng->last_delay.den);
99     }
100
101     avio_wb64(format_context->pb, PNGSIG);
102     // Remaining headers are written when they are copied from the encoder
103
104     return 0;
105 }
106
107 static int flush_packet(AVFormatContext *format_context, AVPacket *packet)
108 {
109     APNGMuxContext *apng = format_context->priv_data;
110     AVIOContext *io_context = format_context->pb;
111     AVStream *codec_stream = format_context->streams[0];
112     uint8_t *side_data = NULL;
113     int side_data_size = 0;
114
115     av_assert0(apng->prev_packet);
116
117     side_data = av_packet_get_side_data(apng->prev_packet, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size);
118
119     if (side_data_size) {
120         av_freep(&apng->extra_data);
121         apng->extra_data = av_mallocz(side_data_size + AV_INPUT_BUFFER_PADDING_SIZE);
122         if (!apng->extra_data)
123             return AVERROR(ENOMEM);
124         apng->extra_data_size = side_data_size;
125         memcpy(apng->extra_data, side_data, apng->extra_data_size);
126     }
127
128     if (apng->frame_number == 0 && !packet) {
129         uint8_t *existing_acTL_chunk;
130         uint8_t *existing_fcTL_chunk;
131
132         av_log(format_context, AV_LOG_INFO, "Only a single frame so saving as a normal PNG.\n");
133
134         // Write normal PNG headers without acTL chunk
135         existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
136         if (existing_acTL_chunk) {
137             uint8_t *chunk_after_acTL = existing_acTL_chunk + AV_RB32(existing_acTL_chunk) + 12;
138             avio_write(io_context, apng->extra_data, existing_acTL_chunk - apng->extra_data);
139             avio_write(io_context, chunk_after_acTL, apng->extra_data + apng->extra_data_size - chunk_after_acTL);
140         } else {
141             avio_write(io_context, apng->extra_data, apng->extra_data_size);
142         }
143
144         // Write frame data without fcTL chunk
145         existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
146         if (existing_fcTL_chunk) {
147             uint8_t *chunk_after_fcTL = existing_fcTL_chunk + AV_RB32(existing_fcTL_chunk) + 12;
148             avio_write(io_context, apng->prev_packet->data, existing_fcTL_chunk - apng->prev_packet->data);
149             avio_write(io_context, chunk_after_fcTL, apng->prev_packet->data + apng->prev_packet->size - chunk_after_fcTL);
150         } else {
151             avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
152         }
153     } else {
154         uint8_t *existing_fcTL_chunk;
155
156         if (apng->frame_number == 0) {
157             uint8_t *existing_acTL_chunk;
158
159             // Write normal PNG headers
160             avio_write(io_context, apng->extra_data, apng->extra_data_size);
161
162             existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
163             if (!existing_acTL_chunk) {
164                 uint8_t buf[8];
165                 // Write animation control header
166                 apng->acTL_offset = avio_tell(io_context);
167                 AV_WB32(buf, UINT_MAX); // number of frames (filled in later)
168                 AV_WB32(buf + 4, apng->plays);
169                 apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
170             }
171         }
172
173         existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
174         if (existing_fcTL_chunk) {
175             AVRational delay;
176
177             existing_fcTL_chunk += 8;
178             delay.num = AV_RB16(existing_fcTL_chunk + 20);
179             delay.den = AV_RB16(existing_fcTL_chunk + 22);
180
181             if (delay.num == 0 && delay.den == 0) {
182                 if (packet) {
183                     int64_t delay_num_raw = (packet->dts - apng->prev_packet->dts) * codec_stream->time_base.num;
184                     int64_t delay_den_raw = codec_stream->time_base.den;
185                     if (!av_reduce(&delay.num, &delay.den, delay_num_raw, delay_den_raw, USHRT_MAX) &&
186                         !apng->framerate_warned) {
187                         av_log(format_context, AV_LOG_WARNING,
188                                "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
189                         apng->framerate_warned = 1;
190                     }
191                 } else if (apng->last_delay.num > 0) {
192                     delay = apng->last_delay;
193                 } else {
194                     delay = apng->prev_delay;
195                 }
196
197                 // Update frame control header with new delay
198                 AV_WB16(existing_fcTL_chunk + 20, delay.num);
199                 AV_WB16(existing_fcTL_chunk + 22, delay.den);
200                 AV_WB32(existing_fcTL_chunk + 26, ~av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), ~0U, existing_fcTL_chunk - 4, 26 + 4));
201             }
202             apng->prev_delay = delay;
203         }
204
205         // Write frame data
206         avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
207     }
208     ++apng->frame_number;
209
210     av_packet_unref(apng->prev_packet);
211     if (packet)
212         av_copy_packet(apng->prev_packet, packet);
213     return 0;
214 }
215
216 static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
217 {
218     APNGMuxContext *apng = format_context->priv_data;
219     int ret;
220
221     if (!apng->prev_packet) {
222         apng->prev_packet = av_malloc(sizeof(*apng->prev_packet));
223         if (!apng->prev_packet)
224             return AVERROR(ENOMEM);
225
226         av_copy_packet(apng->prev_packet, packet);
227     } else {
228         ret = flush_packet(format_context, packet);
229         if (ret < 0)
230             return ret;
231     }
232
233     return 0;
234 }
235
236 static int apng_write_trailer(AVFormatContext *format_context)
237 {
238     APNGMuxContext *apng = format_context->priv_data;
239     AVIOContext *io_context = format_context->pb;
240     uint8_t buf[8];
241     int ret;
242
243     if (apng->prev_packet) {
244         ret = flush_packet(format_context, NULL);
245         av_freep(&apng->prev_packet);
246         if (ret < 0)
247             return ret;
248     }
249
250     apng_write_chunk(io_context, MKBETAG('I', 'E', 'N', 'D'), NULL, 0);
251
252     if (apng->acTL_offset && io_context->seekable) {
253         avio_seek(io_context, apng->acTL_offset, SEEK_SET);
254
255         AV_WB32(buf, apng->frame_number);
256         AV_WB32(buf + 4, apng->plays);
257         apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
258     }
259
260     av_freep(&apng->extra_data);
261     apng->extra_data = 0;
262
263     return 0;
264 }
265
266 #define OFFSET(x) offsetof(APNGMuxContext, x)
267 #define ENC AV_OPT_FLAG_ENCODING_PARAM
268 static const AVOption options[] = {
269     { "plays", "Number of times to play the output: 0 - infinite loop, 1 - no loop", OFFSET(plays),
270       AV_OPT_TYPE_INT, { .i64 = 1 }, 0, UINT_MAX, ENC },
271     { "final_delay", "Force delay after the last frame", OFFSET(last_delay),
272       AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, USHRT_MAX, ENC },
273     { NULL },
274 };
275
276 static const AVClass apng_muxer_class = {
277     .class_name = "APNG muxer",
278     .item_name  = av_default_item_name,
279     .version    = LIBAVUTIL_VERSION_INT,
280     .option     = options,
281 };
282
283 AVOutputFormat ff_apng_muxer = {
284     .name           = "apng",
285     .long_name      = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
286     .mime_type      = "image/png",
287     .extensions     = "apng",
288     .priv_data_size = sizeof(APNGMuxContext),
289     .audio_codec    = AV_CODEC_ID_NONE,
290     .video_codec    = AV_CODEC_ID_APNG,
291     .write_header   = apng_write_header,
292     .write_packet   = apng_write_packet,
293     .write_trailer  = apng_write_trailer,
294     .priv_class     = &apng_muxer_class,
295     .flags          = AVFMT_VARIABLE_FPS,
296 };