Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * AIFF/AIFF-C muxer
  3.  * Copyright (c) 2006  Patrick Guimond
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. #include <stdint.h>
  23.  
  24. #include "libavutil/intfloat.h"
  25. #include "libavutil/opt.h"
  26. #include "avformat.h"
  27. #include "internal.h"
  28. #include "aiff.h"
  29. #include "avio_internal.h"
  30. #include "isom.h"
  31. #include "id3v2.h"
  32.  
  33. typedef struct AIFFOutputContext {
  34.     const AVClass *class;
  35.     int64_t form;
  36.     int64_t frames;
  37.     int64_t ssnd;
  38.     int audio_stream_idx;
  39.     AVPacketList *pict_list;
  40.     int write_id3v2;
  41.     int id3v2_version;
  42. } AIFFOutputContext;
  43.  
  44. static int put_id3v2_tags(AVFormatContext *s, AIFFOutputContext *aiff)
  45. {
  46.     int ret;
  47.     uint64_t pos, end, size;
  48.     ID3v2EncContext id3v2 = { 0 };
  49.     AVIOContext *pb = s->pb;
  50.     AVPacketList *pict_list = aiff->pict_list;
  51.  
  52.     if (!pb->seekable)
  53.         return 0;
  54.  
  55.     if (!s->metadata && !aiff->pict_list)
  56.         return 0;
  57.  
  58.     avio_wl32(pb, MKTAG('I', 'D', '3', ' '));
  59.     avio_wb32(pb, 0);
  60.     pos = avio_tell(pb);
  61.  
  62.     ff_id3v2_start(&id3v2, pb, aiff->id3v2_version, ID3v2_DEFAULT_MAGIC);
  63.     ff_id3v2_write_metadata(s, &id3v2);
  64.     while (pict_list) {
  65.         if ((ret = ff_id3v2_write_apic(s, &id3v2, &pict_list->pkt)) < 0)
  66.             return ret;
  67.         pict_list = pict_list->next;
  68.     }
  69.     ff_id3v2_finish(&id3v2, pb, s->metadata_header_padding);
  70.  
  71.     end = avio_tell(pb);
  72.     size = end - pos;
  73.  
  74.     /* Update chunk size */
  75.     avio_seek(pb, pos - 4, SEEK_SET);
  76.     avio_wb32(pb, size);
  77.     avio_seek(pb, end, SEEK_SET);
  78.  
  79.     if (size & 1)
  80.         avio_w8(pb, 0);
  81.  
  82.     return 0;
  83. }
  84.  
  85. static void put_meta(AVFormatContext *s, const char *key, uint32_t id)
  86. {
  87.     AVDictionaryEntry *tag;
  88.     AVIOContext *pb = s->pb;
  89.  
  90.     if (tag = av_dict_get(s->metadata, key, NULL, 0)) {
  91.         int size = strlen(tag->value);
  92.  
  93.         avio_wl32(pb, id);
  94.         avio_wb32(pb, FFALIGN(size, 2));
  95.         avio_write(pb, tag->value, size);
  96.         if (size & 1)
  97.             avio_w8(pb, 0);
  98.     }
  99. }
  100.  
  101. static int aiff_write_header(AVFormatContext *s)
  102. {
  103.     AIFFOutputContext *aiff = s->priv_data;
  104.     AVIOContext *pb = s->pb;
  105.     AVCodecContext *enc;
  106.     uint64_t sample_rate;
  107.     int i, aifc = 0;
  108.  
  109.     aiff->audio_stream_idx = -1;
  110.     for (i = 0; i < s->nb_streams; i++) {
  111.         AVStream *st = s->streams[i];
  112.         if (aiff->audio_stream_idx < 0 && st->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
  113.             aiff->audio_stream_idx = i;
  114.         } else if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) {
  115.             av_log(s, AV_LOG_ERROR, "AIFF allows only one audio stream and a picture.\n");
  116.             return AVERROR(EINVAL);
  117.         }
  118.     }
  119.     if (aiff->audio_stream_idx < 0) {
  120.         av_log(s, AV_LOG_ERROR, "No audio stream present.\n");
  121.         return AVERROR(EINVAL);
  122.     }
  123.  
  124.     enc = s->streams[aiff->audio_stream_idx]->codec;
  125.  
  126.     /* First verify if format is ok */
  127.     if (!enc->codec_tag)
  128.         return -1;
  129.     if (enc->codec_tag != MKTAG('N','O','N','E'))
  130.         aifc = 1;
  131.  
  132.     /* FORM AIFF header */
  133.     ffio_wfourcc(pb, "FORM");
  134.     aiff->form = avio_tell(pb);
  135.     avio_wb32(pb, 0);                    /* file length */
  136.     ffio_wfourcc(pb, aifc ? "AIFC" : "AIFF");
  137.  
  138.     if (aifc) { // compressed audio
  139.         if (!enc->block_align) {
  140.             av_log(s, AV_LOG_ERROR, "block align not set\n");
  141.             return -1;
  142.         }
  143.         /* Version chunk */
  144.         ffio_wfourcc(pb, "FVER");
  145.         avio_wb32(pb, 4);
  146.         avio_wb32(pb, 0xA2805140);
  147.     }
  148.  
  149.     if (enc->channels > 2 && enc->channel_layout) {
  150.         ffio_wfourcc(pb, "CHAN");
  151.         avio_wb32(pb, 12);
  152.         ff_mov_write_chan(pb, enc->channel_layout);
  153.     }
  154.  
  155.     put_meta(s, "title",     MKTAG('N', 'A', 'M', 'E'));
  156.     put_meta(s, "author",    MKTAG('A', 'U', 'T', 'H'));
  157.     put_meta(s, "copyright", MKTAG('(', 'c', ')', ' '));
  158.     put_meta(s, "comment",   MKTAG('A', 'N', 'N', 'O'));
  159.  
  160.     /* Common chunk */
  161.     ffio_wfourcc(pb, "COMM");
  162.     avio_wb32(pb, aifc ? 24 : 18); /* size */
  163.     avio_wb16(pb, enc->channels);  /* Number of channels */
  164.  
  165.     aiff->frames = avio_tell(pb);
  166.     avio_wb32(pb, 0);              /* Number of frames */
  167.  
  168.     if (!enc->bits_per_coded_sample)
  169.         enc->bits_per_coded_sample = av_get_bits_per_sample(enc->codec_id);
  170.     if (!enc->bits_per_coded_sample) {
  171.         av_log(s, AV_LOG_ERROR, "could not compute bits per sample\n");
  172.         return -1;
  173.     }
  174.     if (!enc->block_align)
  175.         enc->block_align = (enc->bits_per_coded_sample * enc->channels) >> 3;
  176.  
  177.     avio_wb16(pb, enc->bits_per_coded_sample); /* Sample size */
  178.  
  179.     sample_rate = av_double2int(enc->sample_rate);
  180.     avio_wb16(pb, (sample_rate >> 52) + (16383 - 1023));
  181.     avio_wb64(pb, UINT64_C(1) << 63 | sample_rate << 11);
  182.  
  183.     if (aifc) {
  184.         avio_wl32(pb, enc->codec_tag);
  185.         avio_wb16(pb, 0);
  186.     }
  187.  
  188.     if (enc->codec_tag == MKTAG('Q','D','M','2') && enc->extradata_size) {
  189.         ffio_wfourcc(pb, "wave");
  190.         avio_wb32(pb, enc->extradata_size);
  191.         avio_write(pb, enc->extradata, enc->extradata_size);
  192.     }
  193.  
  194.     /* Sound data chunk */
  195.     ffio_wfourcc(pb, "SSND");
  196.     aiff->ssnd = avio_tell(pb);         /* Sound chunk size */
  197.     avio_wb32(pb, 0);                    /* Sound samples data size */
  198.     avio_wb32(pb, 0);                    /* Data offset */
  199.     avio_wb32(pb, 0);                    /* Block-size (block align) */
  200.  
  201.     avpriv_set_pts_info(s->streams[aiff->audio_stream_idx], 64, 1,
  202.                         s->streams[aiff->audio_stream_idx]->codec->sample_rate);
  203.  
  204.     /* Data is starting here */
  205.     avio_flush(pb);
  206.  
  207.     return 0;
  208. }
  209.  
  210. static int aiff_write_packet(AVFormatContext *s, AVPacket *pkt)
  211. {
  212.     AIFFOutputContext *aiff = s->priv_data;
  213.     AVIOContext *pb = s->pb;
  214.     if (pkt->stream_index == aiff->audio_stream_idx)
  215.         avio_write(pb, pkt->data, pkt->size);
  216.     else {
  217.         int ret;
  218.         AVPacketList *pict_list, *last;
  219.  
  220.         if (s->streams[pkt->stream_index]->codec->codec_type != AVMEDIA_TYPE_VIDEO)
  221.             return 0;
  222.  
  223.         /* warn only once for each stream */
  224.         if (s->streams[pkt->stream_index]->nb_frames == 1) {
  225.             av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
  226.                    " ignoring.\n", pkt->stream_index);
  227.         }
  228.         if (s->streams[pkt->stream_index]->nb_frames >= 1)
  229.             return 0;
  230.  
  231.         pict_list = av_mallocz(sizeof(AVPacketList));
  232.         if (!pict_list)
  233.             return AVERROR(ENOMEM);
  234.  
  235.         if ((ret = av_copy_packet(&pict_list->pkt, pkt)) < 0) {
  236.             av_freep(&pict_list);
  237.             return ret;
  238.         }
  239.  
  240.         if (!aiff->pict_list)
  241.             aiff->pict_list = pict_list;
  242.         else {
  243.             last = aiff->pict_list;
  244.             while (last->next)
  245.                 last = last->next;
  246.             last->next = pict_list;
  247.         }
  248.     }
  249.  
  250.     return 0;
  251. }
  252.  
  253. static int aiff_write_trailer(AVFormatContext *s)
  254. {
  255.     int ret;
  256.     AVIOContext *pb = s->pb;
  257.     AIFFOutputContext *aiff = s->priv_data;
  258.     AVPacketList *pict_list = aiff->pict_list;
  259.     AVCodecContext *enc = s->streams[aiff->audio_stream_idx]->codec;
  260.  
  261.     /* Chunks sizes must be even */
  262.     int64_t file_size, end_size;
  263.     end_size = file_size = avio_tell(pb);
  264.     if (file_size & 1) {
  265.         avio_w8(pb, 0);
  266.         end_size++;
  267.     }
  268.  
  269.     if (s->pb->seekable) {
  270.         /* Number of sample frames */
  271.         avio_seek(pb, aiff->frames, SEEK_SET);
  272.         avio_wb32(pb, (file_size-aiff->ssnd-12)/enc->block_align);
  273.  
  274.         /* Sound Data chunk size */
  275.         avio_seek(pb, aiff->ssnd, SEEK_SET);
  276.         avio_wb32(pb, file_size - aiff->ssnd - 4);
  277.  
  278.         /* return to the end */
  279.         avio_seek(pb, end_size, SEEK_SET);
  280.  
  281.         /* Write ID3 tags */
  282.         if (aiff->write_id3v2)
  283.             if ((ret = put_id3v2_tags(s, aiff)) < 0)
  284.                 return ret;
  285.  
  286.         /* File length */
  287.         file_size = avio_tell(pb);
  288.         avio_seek(pb, aiff->form, SEEK_SET);
  289.         avio_wb32(pb, file_size - aiff->form - 4);
  290.  
  291.         avio_flush(pb);
  292.     }
  293.  
  294.     while (pict_list) {
  295.         AVPacketList *next = pict_list->next;
  296.         av_free_packet(&pict_list->pkt);
  297.         av_freep(&pict_list);
  298.         pict_list = next;
  299.     }
  300.  
  301.     return 0;
  302. }
  303.  
  304. #define OFFSET(x) offsetof(AIFFOutputContext, x)
  305. #define ENC AV_OPT_FLAG_ENCODING_PARAM
  306. static const AVOption options[] = {
  307.     { "write_id3v2", "Enable ID3 tags writing.",
  308.       OFFSET(write_id3v2), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, ENC },
  309.     { "id3v2_version", "Select ID3v2 version to write. Currently 3 and 4 are supported.",
  310.       OFFSET(id3v2_version), AV_OPT_TYPE_INT, {.i64 = 4}, 3, 4, ENC },
  311.     { NULL },
  312. };
  313.  
  314. static const AVClass aiff_muxer_class = {
  315.     .class_name     = "AIFF muxer",
  316.     .item_name      = av_default_item_name,
  317.     .option         = options,
  318.     .version        = LIBAVUTIL_VERSION_INT,
  319. };
  320.  
  321. AVOutputFormat ff_aiff_muxer = {
  322.     .name              = "aiff",
  323.     .long_name         = NULL_IF_CONFIG_SMALL("Audio IFF"),
  324.     .mime_type         = "audio/aiff",
  325.     .extensions        = "aif,aiff,afc,aifc",
  326.     .priv_data_size    = sizeof(AIFFOutputContext),
  327.     .audio_codec       = AV_CODEC_ID_PCM_S16BE,
  328.     .video_codec       = AV_CODEC_ID_PNG,
  329.     .write_header      = aiff_write_header,
  330.     .write_packet      = aiff_write_packet,
  331.     .write_trailer     = aiff_write_trailer,
  332.     .codec_tag         = (const AVCodecTag* const []){ ff_codec_aiff_tags, 0 },
  333.     .priv_class        = &aiff_muxer_class,
  334. };
  335.