Subversion Repositories Kolibri OS

Rev

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