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
33
36
39
42
45
47
51
53 size_t length)
54 {
60 }
61
63 uint8_t *buf, size_t length)
64 {
67 uint8_t tagbuf[4];
68
70
73 crc =
av_crc(crc_table, crc, tagbuf, 4);
75 if (length > 0) {
76 crc =
av_crc(crc_table, crc, buf, length);
78 }
80 }
81
83 {
86
91 "Last frame delay is too precise. Reducing to %d/%d (%f).\n",
93 }
94
96 // Remaining headers are written when they are copied from the encoder
97
104 }
105
106 return 0;
107 }
108
110 {
114 uint8_t *side_data =
NULL;
115 size_t side_data_size;
116
118
120
121 if (side_data_size) {
128 }
129
131 const uint8_t *existing_acTL_chunk;
132 const uint8_t *existing_fcTL_chunk;
133
134 av_log(format_context,
AV_LOG_INFO,
"Only a single frame so saving as a normal PNG.\n");
135
136 // Write normal PNG headers without acTL chunk
138 if (existing_acTL_chunk) {
139 const uint8_t *chunk_after_acTL = existing_acTL_chunk +
AV_RB32(existing_acTL_chunk) + 12;
142 } else {
144 }
145
146 // Write frame data without fcTL chunk
148 if (existing_fcTL_chunk) {
149 const uint8_t *chunk_after_fcTL = existing_fcTL_chunk +
AV_RB32(existing_fcTL_chunk) + 12;
152 } else {
154 }
155 } else {
156 const uint8_t *
data, *data_end;
157 const uint8_t *existing_fcTL_chunk;
158
160 const uint8_t *existing_acTL_chunk;
161
162 // Write normal PNG headers
164
166 if (!existing_acTL_chunk) {
167 uint8_t buf[8];
168 // Write animation control header
170 AV_WB32(buf, UINT_MAX);
// number of frames (filled in later)
173 }
174 }
175
179 if (existing_fcTL_chunk) {
181
184
185 existing_fcTL_chunk += 8;
186 delay.
num =
AV_RB16(existing_fcTL_chunk + 20);
187 delay.
den =
AV_RB16(existing_fcTL_chunk + 22);
188
189 if (delay.
num == 0 && delay.
den == 0) {
191
195 if (!
av_reduce(&delay.
num, &delay.
den, delay_num_raw, delay_den_raw, UINT16_MAX) &&
198 "Frame rate is too high or specified too precisely. Unable to copy losslessly.\n");
200 }
203 } else {
205 }
206
209 // Update frame control header with new delay
210 memcpy(new_fcTL_chunk, existing_fcTL_chunk, sizeof(new_fcTL_chunk));
214 new_fcTL_chunk, sizeof(new_fcTL_chunk));
215 }
217 }
218
219 // Write frame data
221 }
223
227 return 0;
228 }
229
231 {
234
239
241 } else {
245 }
246
247 return 0;
248 }
249
251 {
254 uint8_t buf[8];
256
261 }
262
264
267
271 }
272
273 return 0;
274 }
275
277 {
279
283 }
284
285 #define OFFSET(x) offsetof(APNGMuxContext, x)
286 #define ENC AV_OPT_FLAG_ENCODING_PARAM
288 {
"plays",
"Number of times to play the output: 0 - infinite loop, 1 - no loop",
OFFSET(plays),
290 {
"final_delay",
"Force delay after the last frame",
OFFSET(last_delay),
293 };
294
300 };
301
305 .p.mime_type = "image/png",
306 .p.extensions = "apng",
319 };