Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. } APNGMuxContext;
  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]->codec->codec_type != AVMEDIA_TYPE_VIDEO ||
  84.         format_context->streams[0]->codec->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.     AVCodecContext *codec_context = codec_stream->codec;
  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_context->extradata, codec_context->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_context->extradata, existing_acTL_chunk - codec_context->extradata);
  124.             avio_write(io_context, chunk_after_acTL, codec_context->extradata + codec_context->extradata_size - chunk_after_acTL);
  125.         } else {
  126.             avio_write(io_context, codec_context->extradata, codec_context->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_context->extradata, codec_context->extradata_size);
  146.  
  147.             existing_acTL_chunk = apng_find_chunk(MKBETAG('a', 'c', 'T', 'L'), codec_context->extradata, codec_context->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.  
  195.     av_free_packet(apng->prev_packet);
  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.  
  258. AVOutputFormat ff_apng_muxer = {
  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,
  266.     .write_header   = apng_write_header,
  267.     .write_packet   = apng_write_packet,
  268.     .write_trailer  = apng_write_trailer,
  269.     .priv_class     = &apng_muxer_class,
  270.     .flags          = AVFMT_VARIABLE_FPS,
  271. };
  272.