Libav 0.7.1
|
00001 /* 00002 * AU muxer and demuxer 00003 * Copyright (c) 2001 Fabrice Bellard 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 /* 00023 * First version by Francois Revol revol@free.fr 00024 * 00025 * Reference documents: 00026 * http://www.opengroup.org/public/pubs/external/auformat.html 00027 * http://www.goice.co.jp/member/mo/formats/au.html 00028 */ 00029 00030 #include "avformat.h" 00031 #include "avio_internal.h" 00032 #include "pcm.h" 00033 #include "riff.h" 00034 00035 /* if we don't know the size in advance */ 00036 #define AU_UNKNOWN_SIZE ((uint32_t)(~0)) 00037 00038 /* The ffmpeg codecs we support, and the IDs they have in the file */ 00039 static const AVCodecTag codec_au_tags[] = { 00040 { CODEC_ID_PCM_MULAW, 1 }, 00041 { CODEC_ID_PCM_S8, 2 }, 00042 { CODEC_ID_PCM_S16BE, 3 }, 00043 { CODEC_ID_PCM_S24BE, 4 }, 00044 { CODEC_ID_PCM_S32BE, 5 }, 00045 { CODEC_ID_PCM_F32BE, 6 }, 00046 { CODEC_ID_PCM_F64BE, 7 }, 00047 { CODEC_ID_PCM_ALAW, 27 }, 00048 { CODEC_ID_NONE, 0 }, 00049 }; 00050 00051 #if CONFIG_AU_MUXER 00052 /* AUDIO_FILE header */ 00053 static int put_au_header(AVIOContext *pb, AVCodecContext *enc) 00054 { 00055 if(!enc->codec_tag) 00056 return -1; 00057 ffio_wfourcc(pb, ".snd"); /* magic number */ 00058 avio_wb32(pb, 24); /* header size */ 00059 avio_wb32(pb, AU_UNKNOWN_SIZE); /* data size */ 00060 avio_wb32(pb, (uint32_t)enc->codec_tag); /* codec ID */ 00061 avio_wb32(pb, enc->sample_rate); 00062 avio_wb32(pb, (uint32_t)enc->channels); 00063 return 0; 00064 } 00065 00066 static int au_write_header(AVFormatContext *s) 00067 { 00068 AVIOContext *pb = s->pb; 00069 00070 s->priv_data = NULL; 00071 00072 /* format header */ 00073 if (put_au_header(pb, s->streams[0]->codec) < 0) { 00074 return -1; 00075 } 00076 00077 avio_flush(pb); 00078 00079 return 0; 00080 } 00081 00082 static int au_write_packet(AVFormatContext *s, AVPacket *pkt) 00083 { 00084 AVIOContext *pb = s->pb; 00085 avio_write(pb, pkt->data, pkt->size); 00086 return 0; 00087 } 00088 00089 static int au_write_trailer(AVFormatContext *s) 00090 { 00091 AVIOContext *pb = s->pb; 00092 int64_t file_size; 00093 00094 if (s->pb->seekable) { 00095 00096 /* update file size */ 00097 file_size = avio_tell(pb); 00098 avio_seek(pb, 8, SEEK_SET); 00099 avio_wb32(pb, (uint32_t)(file_size - 24)); 00100 avio_seek(pb, file_size, SEEK_SET); 00101 00102 avio_flush(pb); 00103 } 00104 00105 return 0; 00106 } 00107 #endif /* CONFIG_AU_MUXER */ 00108 00109 static int au_probe(AVProbeData *p) 00110 { 00111 /* check file header */ 00112 if (p->buf[0] == '.' && p->buf[1] == 's' && 00113 p->buf[2] == 'n' && p->buf[3] == 'd') 00114 return AVPROBE_SCORE_MAX; 00115 else 00116 return 0; 00117 } 00118 00119 /* au input */ 00120 static int au_read_header(AVFormatContext *s, 00121 AVFormatParameters *ap) 00122 { 00123 int size; 00124 unsigned int tag; 00125 AVIOContext *pb = s->pb; 00126 unsigned int id, channels, rate; 00127 enum CodecID codec; 00128 AVStream *st; 00129 00130 /* check ".snd" header */ 00131 tag = avio_rl32(pb); 00132 if (tag != MKTAG('.', 's', 'n', 'd')) 00133 return -1; 00134 size = avio_rb32(pb); /* header size */ 00135 avio_rb32(pb); /* data size */ 00136 00137 id = avio_rb32(pb); 00138 rate = avio_rb32(pb); 00139 channels = avio_rb32(pb); 00140 00141 codec = ff_codec_get_id(codec_au_tags, id); 00142 00143 if (!av_get_bits_per_sample(codec)) { 00144 av_log_ask_for_sample(s, "could not determine bits per sample\n"); 00145 return AVERROR_INVALIDDATA; 00146 } 00147 00148 if (size >= 24) { 00149 /* skip unused data */ 00150 avio_skip(pb, size - 24); 00151 } 00152 00153 /* now we are ready: build format streams */ 00154 st = av_new_stream(s, 0); 00155 if (!st) 00156 return -1; 00157 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00158 st->codec->codec_tag = id; 00159 st->codec->codec_id = codec; 00160 st->codec->channels = channels; 00161 st->codec->sample_rate = rate; 00162 av_set_pts_info(st, 64, 1, rate); 00163 return 0; 00164 } 00165 00166 #define BLOCK_SIZE 1024 00167 00168 static int au_read_packet(AVFormatContext *s, 00169 AVPacket *pkt) 00170 { 00171 int ret; 00172 00173 ret= av_get_packet(s->pb, pkt, BLOCK_SIZE * 00174 s->streams[0]->codec->channels * 00175 av_get_bits_per_sample(s->streams[0]->codec->codec_id) >> 3); 00176 if (ret < 0) 00177 return ret; 00178 pkt->stream_index = 0; 00179 00180 /* note: we need to modify the packet size here to handle the last 00181 packet */ 00182 pkt->size = ret; 00183 return 0; 00184 } 00185 00186 #if CONFIG_AU_DEMUXER 00187 AVInputFormat ff_au_demuxer = { 00188 "au", 00189 NULL_IF_CONFIG_SMALL("SUN AU format"), 00190 0, 00191 au_probe, 00192 au_read_header, 00193 au_read_packet, 00194 NULL, 00195 pcm_read_seek, 00196 .codec_tag= (const AVCodecTag* const []){codec_au_tags, 0}, 00197 }; 00198 #endif 00199 00200 #if CONFIG_AU_MUXER 00201 AVOutputFormat ff_au_muxer = { 00202 "au", 00203 NULL_IF_CONFIG_SMALL("SUN AU format"), 00204 "audio/basic", 00205 "au", 00206 0, 00207 CODEC_ID_PCM_S16BE, 00208 CODEC_ID_NONE, 00209 au_write_header, 00210 au_write_packet, 00211 au_write_trailer, 00212 .codec_tag= (const AVCodecTag* const []){codec_au_tags, 0}, 00213 }; 00214 #endif //CONFIG_AU_MUXER