Imported Upstream version 6.1
[platform/upstream/ffmpeg.git] / 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 "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/opt.h"
31 #include "libavcodec/apng.h"
32 #include "libavcodec/png.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 const uint8_t *apng_find_chunk(uint32_t tag, const uint8_t *buf,
53                                       size_t length)
54 {
55     size_t b;
56     for (b = 0; AV_RB32(buf + b) + 12ULL <= length - b; b += AV_RB32(buf + b) + 12ULL)
57         if (AV_RB32(&buf[b + 4]) == tag)
58             return &buf[b];
59     return NULL;
60 }
61
62 static void apng_write_chunk(AVIOContext *io_context, uint32_t tag,
63                              uint8_t *buf, size_t length)
64 {
65     const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
66     uint32_t crc = ~0U;
67     uint8_t tagbuf[4];
68
69     av_assert0(crc_table);
70
71     avio_wb32(io_context, length);
72     AV_WB32(tagbuf, tag);
73     crc = av_crc(crc_table, crc, tagbuf, 4);
74     avio_wb32(io_context, tag);
75     if (length > 0) {
76         crc = av_crc(crc_table, crc, buf, length);
77         avio_write(io_context, buf, length);
78     }
79     avio_wb32(io_context, ~crc);
80 }
81
82 static int apng_write_header(AVFormatContext *format_context)
83 {
84     APNGMuxContext *apng = format_context->priv_data;
85     AVCodecParameters *par = format_context->streams[0]->codecpar;
86
87     if (format_context->nb_streams != 1 ||
88         format_context->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
89         format_context->streams[0]->codecpar->codec_id   != AV_CODEC_ID_APNG) {
90         av_log(format_context, AV_LOG_ERROR,
91                "APNG muxer supports only a single video APNG stream.\n");
92         return AVERROR(EINVAL);
93     }
94
95     if (apng->last_delay.num > UINT16_MAX || apng->last_delay.den > UINT16_MAX) {
96         av_reduce(&apng->last_delay.num, &apng->last_delay.den,
97                   apng->last_delay.num, apng->last_delay.den, UINT16_MAX);
98         av_log(format_context, AV_LOG_WARNING,
99                "Last frame delay is too precise. Reducing to %d/%d (%f).\n",
100                apng->last_delay.num, apng->last_delay.den, (double)apng->last_delay.num / apng->last_delay.den);
101     }
102
103     avio_wb64(format_context->pb, PNGSIG);
104     // Remaining headers are written when they are copied from the encoder
105
106     if (par->extradata_size) {
107         apng->extra_data = av_mallocz(par->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
108         if (!apng->extra_data)
109             return AVERROR(ENOMEM);
110         apng->extra_data_size = par->extradata_size;
111         memcpy(apng->extra_data, par->extradata, par->extradata_size);
112     }
113
114     return 0;
115 }
116
117 static int flush_packet(AVFormatContext *format_context, AVPacket *packet)
118 {
119     APNGMuxContext *apng = format_context->priv_data;
120     AVIOContext *io_context = format_context->pb;
121     AVStream *codec_stream = format_context->streams[0];
122     uint8_t *side_data = NULL;
123     size_t side_data_size;
124
125     av_assert0(apng->prev_packet);
126
127     side_data = av_packet_get_side_data(apng->prev_packet, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size);
128
129     if (side_data_size) {
130         av_freep(&apng->extra_data);
131         apng->extra_data = av_mallocz(side_data_size + AV_INPUT_BUFFER_PADDING_SIZE);
132         if (!apng->extra_data)
133             return AVERROR(ENOMEM);
134         apng->extra_data_size = side_data_size;
135         memcpy(apng->extra_data, side_data, apng->extra_data_size);
136     }
137
138     if (apng->frame_number == 0 && !packet) {
139         const uint8_t *existing_acTL_chunk;
140         const uint8_t *existing_fcTL_chunk;
141
142         av_log(format_context, AV_LOG_INFO, "Only a single frame so saving as a normal PNG.\n");
143
144         // Write normal PNG headers without acTL chunk
145         existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
146         if (existing_acTL_chunk) {
147             const uint8_t *chunk_after_acTL = existing_acTL_chunk + AV_RB32(existing_acTL_chunk) + 12;
148             avio_write(io_context, apng->extra_data, existing_acTL_chunk - apng->extra_data);
149             avio_write(io_context, chunk_after_acTL, apng->extra_data + apng->extra_data_size - chunk_after_acTL);
150         } else {
151             avio_write(io_context, apng->extra_data, apng->extra_data_size);
152         }
153
154         // Write frame data without fcTL chunk
155         existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
156         if (existing_fcTL_chunk) {
157             const uint8_t *chunk_after_fcTL = existing_fcTL_chunk + AV_RB32(existing_fcTL_chunk) + 12;
158             avio_write(io_context, apng->prev_packet->data, existing_fcTL_chunk - apng->prev_packet->data);
159             avio_write(io_context, chunk_after_fcTL, apng->prev_packet->data + apng->prev_packet->size - chunk_after_fcTL);
160         } else {
161             avio_write(io_context, apng->prev_packet->data, apng->prev_packet->size);
162         }
163     } else {
164         const uint8_t *data, *data_end;
165         const uint8_t *existing_fcTL_chunk;
166
167         if (apng->frame_number == 0) {
168             const uint8_t *existing_acTL_chunk;
169
170             // Write normal PNG headers
171             avio_write(io_context, apng->extra_data, apng->extra_data_size);
172
173             existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), apng->extra_data, apng->extra_data_size);
174             if (!existing_acTL_chunk) {
175                 uint8_t buf[8];
176                 // Write animation control header
177                 apng->acTL_offset = avio_tell(io_context);
178                 AV_WB32(buf, UINT_MAX); // number of frames (filled in later)
179                 AV_WB32(buf + 4, apng->plays);
180                 apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
181             }
182         }
183
184         data     = apng->prev_packet->data;
185         data_end = data + apng->prev_packet->size;
186         existing_fcTL_chunk = apng_find_chunk(MKBETAG('f', 'c', 'T', 'L'), apng->prev_packet->data, apng->prev_packet->size);
187         if (existing_fcTL_chunk) {
188             AVRational delay;
189
190             if (AV_RB32(existing_fcTL_chunk) != APNG_FCTL_CHUNK_SIZE)
191                 return AVERROR_INVALIDDATA;
192
193             existing_fcTL_chunk += 8;
194             delay.num = AV_RB16(existing_fcTL_chunk + 20);
195             delay.den = AV_RB16(existing_fcTL_chunk + 22);
196
197             if (delay.num == 0 && delay.den == 0) {
198                 uint8_t new_fcTL_chunk[APNG_FCTL_CHUNK_SIZE];
199
200                 if (packet) {
201                     int64_t delay_num_raw = (packet->dts - apng->prev_packet->dts) * codec_stream->time_base.num;
202                     int64_t delay_den_raw = codec_stream->time_base.den;
203                     if (!av_reduce(&delay.num, &delay.den, delay_num_raw, delay_den_raw, UINT16_MAX) &&
204                         !apng->framerate_warned) {
205                         av_log(format_context, AV_LOG_WARNING,
206                                "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
207                         apng->framerate_warned = 1;
208                     }
209                 } else if (apng->last_delay.num > 0) {
210                     delay = apng->last_delay;
211                 } else {
212                     delay = apng->prev_delay;
213                 }
214
215                 avio_write(io_context, data, (existing_fcTL_chunk - 8) - data);
216                 data = existing_fcTL_chunk + APNG_FCTL_CHUNK_SIZE + 4 /* CRC-32 */;
217                 // Update frame control header with new delay
218                 memcpy(new_fcTL_chunk, existing_fcTL_chunk, sizeof(new_fcTL_chunk));
219                 AV_WB16(new_fcTL_chunk + 20, delay.num);
220                 AV_WB16(new_fcTL_chunk + 22, delay.den);
221                 apng_write_chunk(io_context, MKBETAG('f', 'c', 'T', 'L'),
222                                  new_fcTL_chunk, sizeof(new_fcTL_chunk));
223             }
224             apng->prev_delay = delay;
225         }
226
227         // Write frame data
228         avio_write(io_context, data, data_end - data);
229     }
230     ++apng->frame_number;
231
232     av_packet_unref(apng->prev_packet);
233     if (packet)
234         av_packet_ref(apng->prev_packet, packet);
235     return 0;
236 }
237
238 static int apng_write_packet(AVFormatContext *format_context, AVPacket *packet)
239 {
240     APNGMuxContext *apng = format_context->priv_data;
241     int ret;
242
243     if (!apng->prev_packet) {
244         apng->prev_packet = av_packet_alloc();
245         if (!apng->prev_packet)
246             return AVERROR(ENOMEM);
247
248         av_packet_ref(apng->prev_packet, packet);
249     } else {
250         ret = flush_packet(format_context, packet);
251         if (ret < 0)
252             return ret;
253     }
254
255     return 0;
256 }
257
258 static int apng_write_trailer(AVFormatContext *format_context)
259 {
260     APNGMuxContext *apng = format_context->priv_data;
261     AVIOContext *io_context = format_context->pb;
262     uint8_t buf[8];
263     int ret;
264
265     if (apng->prev_packet) {
266         ret = flush_packet(format_context, NULL);
267         if (ret < 0)
268             return ret;
269     }
270
271     apng_write_chunk(io_context, MKBETAG('I', 'E', 'N', 'D'), NULL, 0);
272
273     if (apng->acTL_offset && (io_context->seekable & AVIO_SEEKABLE_NORMAL)) {
274         avio_seek(io_context, apng->acTL_offset, SEEK_SET);
275
276         AV_WB32(buf, apng->frame_number);
277         AV_WB32(buf + 4, apng->plays);
278         apng_write_chunk(io_context, MKBETAG('a', 'c', 'T', 'L'), buf, 8);
279     }
280
281     return 0;
282 }
283
284 static void apng_deinit(AVFormatContext *s)
285 {
286     APNGMuxContext *apng = s->priv_data;
287
288     av_packet_free(&apng->prev_packet);
289     av_freep(&apng->extra_data);
290     apng->extra_data_size = 0;
291 }
292
293 #define OFFSET(x) offsetof(APNGMuxContext, x)
294 #define ENC AV_OPT_FLAG_ENCODING_PARAM
295 static const AVOption options[] = {
296     { "plays", "Number of times to play the output: 0 - infinite loop, 1 - no loop", OFFSET(plays),
297       AV_OPT_TYPE_INT, { .i64 = 1 }, 0, UINT16_MAX, ENC },
298     { "final_delay", "Force delay after the last frame", OFFSET(last_delay),
299       AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, UINT16_MAX, ENC },
300     { NULL },
301 };
302
303 static const AVClass apng_muxer_class = {
304     .class_name = "APNG muxer",
305     .item_name  = av_default_item_name,
306     .version    = LIBAVUTIL_VERSION_INT,
307     .option     = options,
308 };
309
310 const FFOutputFormat ff_apng_muxer = {
311     .p.name         = "apng",
312     .p.long_name    = NULL_IF_CONFIG_SMALL("Animated Portable Network Graphics"),
313     .p.mime_type    = "image/png",
314     .p.extensions   = "apng",
315     .priv_data_size = sizeof(APNGMuxContext),
316     .p.audio_codec  = AV_CODEC_ID_NONE,
317     .p.video_codec  = AV_CODEC_ID_APNG,
318     .write_header   = apng_write_header,
319     .write_packet   = apng_write_packet,
320     .write_trailer  = apng_write_trailer,
321     .deinit         = apng_deinit,
322     .p.priv_class   = &apng_muxer_class,
323     .p.flags        = AVFMT_VARIABLE_FPS,
324 };