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
34
37
40
43
46
48
52
54 size_t length)
55 {
61 }
62
64 uint8_t *buf, size_t length)
65 {
68 uint8_t tagbuf[4];
69
71
74 crc =
av_crc(crc_table, crc, tagbuf, 4);
76 if (length > 0) {
77 crc =
av_crc(crc_table, crc, buf, length);
79 }
81 }
82
84 {
87
92 "Last frame delay is too precise. Reducing to %d/%d (%f).\n",
94 }
95
97 // Remaining headers are written when they are copied from the encoder
98
105 }
106
107 return 0;
108 }
109
111 {
115 uint8_t *side_data =
NULL;
116 size_t side_data_size;
117
119
121
122 if (side_data_size) {
129 }
130
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
139 if (existing_acTL_chunk) {
140 const uint8_t *chunk_after_acTL = existing_acTL_chunk +
AV_RB32(existing_acTL_chunk) + 12;
143 } else {
145 }
146
147 // Write frame data without fcTL chunk
149 if (existing_fcTL_chunk) {
150 const uint8_t *chunk_after_fcTL = existing_fcTL_chunk +
AV_RB32(existing_fcTL_chunk) + 12;
153 } else {
155 }
156 } else {
157 const uint8_t *
data, *data_end;
158 const uint8_t *existing_fcTL_chunk;
159
161 const uint8_t *existing_acTL_chunk;
162
163 // Write normal PNG headers
165
167 if (!existing_acTL_chunk) {
168 uint8_t buf[8];
169 // Write animation control header
171 AV_WB32(buf, UINT_MAX);
// number of frames (filled in later)
174 }
175 }
176
180 if (existing_fcTL_chunk) {
182
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) {
192
193 if (packet) {
196 if (!
av_reduce(&delay.
num, &delay.
den, delay_num_raw, delay_den_raw, UINT16_MAX) &&
199 "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
201 }
204 } else {
206 }
207
210 // Update frame control header with new delay
211 memcpy(new_fcTL_chunk, existing_fcTL_chunk, sizeof(new_fcTL_chunk));
215 new_fcTL_chunk, sizeof(new_fcTL_chunk));
216 }
218 }
219
220 // Write frame data
222 }
224
226 if (packet)
228 return 0;
229 }
230
232 {
235
240
242 } else {
246 }
247
248 return 0;
249 }
250
252 {
255 uint8_t buf[8];
257
262 }
263
265
268
272 }
273
274 return 0;
275 }
276
278 {
280
284 }
285
286 #define OFFSET(x) offsetof(APNGMuxContext, x)
287 #define ENC AV_OPT_FLAG_ENCODING_PARAM
289 {
"plays",
"Number of times to play the output: 0 - infinite loop, 1 - no loop",
OFFSET(plays),
291 {
"final_delay",
"Force delay after the last frame",
OFFSET(last_delay),
294 };
295
301 };
302
306 .p.mime_type = "image/png",
307 .p.extensions = "apng",
320 };