00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "avformat.h"
00023 #include "aiff.h"
00024
00025 typedef struct {
00026 int64_t form;
00027 int64_t frames;
00028 int64_t ssnd;
00029 } AIFFOutputContext;
00030
00031 static int aiff_write_header(AVFormatContext *s)
00032 {
00033 AIFFOutputContext *aiff = s->priv_data;
00034 ByteIOContext *pb = s->pb;
00035 AVCodecContext *enc = s->streams[0]->codec;
00036 AVExtFloat sample_rate;
00037 int aifc = 0;
00038
00039
00040 if (!enc->codec_tag)
00041 return -1;
00042 if (enc->codec_tag != MKTAG('N','O','N','E'))
00043 aifc = 1;
00044
00045
00046 put_tag(pb, "FORM");
00047 aiff->form = url_ftell(pb);
00048 put_be32(pb, 0);
00049 put_tag(pb, aifc ? "AIFC" : "AIFF");
00050
00051 if (aifc) {
00052 enc->bits_per_coded_sample = 16;
00053 if (!enc->block_align) {
00054 av_log(s, AV_LOG_ERROR, "block align not set\n");
00055 return -1;
00056 }
00057
00058 put_tag(pb, "FVER");
00059 put_be32(pb, 4);
00060 put_be32(pb, 0xA2805140);
00061 }
00062
00063
00064 put_tag(pb, "COMM");
00065 put_be32(pb, aifc ? 24 : 18);
00066 put_be16(pb, enc->channels);
00067
00068 aiff->frames = url_ftell(pb);
00069 put_be32(pb, 0);
00070
00071 if (!enc->bits_per_coded_sample)
00072 enc->bits_per_coded_sample = av_get_bits_per_sample(enc->codec_id);
00073 if (!enc->bits_per_coded_sample) {
00074 av_log(s, AV_LOG_ERROR, "could not compute bits per sample\n");
00075 return -1;
00076 }
00077 if (!enc->block_align)
00078 enc->block_align = (enc->bits_per_coded_sample * enc->channels) >> 3;
00079
00080 put_be16(pb, enc->bits_per_coded_sample);
00081
00082 sample_rate = av_dbl2ext((double)enc->sample_rate);
00083 put_buffer(pb, (uint8_t*)&sample_rate, sizeof(sample_rate));
00084
00085 if (aifc) {
00086 put_le32(pb, enc->codec_tag);
00087 put_be16(pb, 0);
00088 }
00089
00090
00091 put_tag(pb, "SSND");
00092 aiff->ssnd = url_ftell(pb);
00093 put_be32(pb, 0);
00094 put_be32(pb, 0);
00095 put_be32(pb, 0);
00096
00097 av_set_pts_info(s->streams[0], 64, 1, s->streams[0]->codec->sample_rate);
00098
00099
00100 put_flush_packet(pb);
00101
00102 return 0;
00103 }
00104
00105 static int aiff_write_packet(AVFormatContext *s, AVPacket *pkt)
00106 {
00107 ByteIOContext *pb = s->pb;
00108 put_buffer(pb, pkt->data, pkt->size);
00109 return 0;
00110 }
00111
00112 static int aiff_write_trailer(AVFormatContext *s)
00113 {
00114 ByteIOContext *pb = s->pb;
00115 AIFFOutputContext *aiff = s->priv_data;
00116 AVCodecContext *enc = s->streams[0]->codec;
00117
00118
00119 int64_t file_size, end_size;
00120 end_size = file_size = url_ftell(pb);
00121 if (file_size & 1) {
00122 put_byte(pb, 0);
00123 end_size++;
00124 }
00125
00126 if (!url_is_streamed(s->pb)) {
00127
00128 url_fseek(pb, aiff->form, SEEK_SET);
00129 put_be32(pb, file_size - aiff->form - 4);
00130
00131
00132 url_fseek(pb, aiff->frames, SEEK_SET);
00133 put_be32(pb, (file_size-aiff->ssnd-12)/enc->block_align);
00134
00135
00136 url_fseek(pb, aiff->ssnd, SEEK_SET);
00137 put_be32(pb, file_size - aiff->ssnd - 4);
00138
00139
00140 url_fseek(pb, end_size, SEEK_SET);
00141
00142 put_flush_packet(pb);
00143 }
00144
00145 return 0;
00146 }
00147
00148 AVOutputFormat aiff_muxer = {
00149 "aiff",
00150 NULL_IF_CONFIG_SMALL("Audio IFF"),
00151 "audio/aiff",
00152 "aif,aiff,afc,aifc",
00153 sizeof(AIFFOutputContext),
00154 CODEC_ID_PCM_S16BE,
00155 CODEC_ID_NONE,
00156 aiff_write_header,
00157 aiff_write_packet,
00158 aiff_write_trailer,
00159 .codec_tag= (const AVCodecTag* const []){ff_codec_aiff_tags, 0},
00160 };