Libav
|
00001 /* 00002 * AU muxer and demuxer 00003 * Copyright (c) 2001 Fabrice Bellard 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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 "raw.h" 00032 #include "riff.h" 00033 00034 /* if we don't know the size in advance */ 00035 #define AU_UNKNOWN_SIZE ((uint32_t)(~0)) 00036 00037 /* The ffmpeg codecs we support, and the IDs they have in the file */ 00038 static const AVCodecTag codec_au_tags[] = { 00039 { CODEC_ID_PCM_MULAW, 1 }, 00040 { CODEC_ID_PCM_S8, 2 }, 00041 { CODEC_ID_PCM_S16BE, 3 }, 00042 { CODEC_ID_PCM_S24BE, 4 }, 00043 { CODEC_ID_PCM_S32BE, 5 }, 00044 { CODEC_ID_PCM_F32BE, 6 }, 00045 { CODEC_ID_PCM_F64BE, 7 }, 00046 { CODEC_ID_PCM_ALAW, 27 }, 00047 { CODEC_ID_NONE, 0 }, 00048 }; 00049 00050 #if CONFIG_AU_MUXER 00051 /* AUDIO_FILE header */ 00052 static int put_au_header(ByteIOContext *pb, AVCodecContext *enc) 00053 { 00054 if(!enc->codec_tag) 00055 return -1; 00056 put_tag(pb, ".snd"); /* magic number */ 00057 put_be32(pb, 24); /* header size */ 00058 put_be32(pb, AU_UNKNOWN_SIZE); /* data size */ 00059 put_be32(pb, (uint32_t)enc->codec_tag); /* codec ID */ 00060 put_be32(pb, enc->sample_rate); 00061 put_be32(pb, (uint32_t)enc->channels); 00062 return 0; 00063 } 00064 00065 static int au_write_header(AVFormatContext *s) 00066 { 00067 ByteIOContext *pb = s->pb; 00068 00069 s->priv_data = NULL; 00070 00071 /* format header */ 00072 if (put_au_header(pb, s->streams[0]->codec) < 0) { 00073 return -1; 00074 } 00075 00076 put_flush_packet(pb); 00077 00078 return 0; 00079 } 00080 00081 static int au_write_packet(AVFormatContext *s, AVPacket *pkt) 00082 { 00083 ByteIOContext *pb = s->pb; 00084 put_buffer(pb, pkt->data, pkt->size); 00085 return 0; 00086 } 00087 00088 static int au_write_trailer(AVFormatContext *s) 00089 { 00090 ByteIOContext *pb = s->pb; 00091 int64_t file_size; 00092 00093 if (!url_is_streamed(s->pb)) { 00094 00095 /* update file size */ 00096 file_size = url_ftell(pb); 00097 url_fseek(pb, 8, SEEK_SET); 00098 put_be32(pb, (uint32_t)(file_size - 24)); 00099 url_fseek(pb, file_size, SEEK_SET); 00100 00101 put_flush_packet(pb); 00102 } 00103 00104 return 0; 00105 } 00106 #endif /* CONFIG_AU_MUXER */ 00107 00108 static int au_probe(AVProbeData *p) 00109 { 00110 /* check file header */ 00111 if (p->buf[0] == '.' && p->buf[1] == 's' && 00112 p->buf[2] == 'n' && p->buf[3] == 'd') 00113 return AVPROBE_SCORE_MAX; 00114 else 00115 return 0; 00116 } 00117 00118 /* au input */ 00119 static int au_read_header(AVFormatContext *s, 00120 AVFormatParameters *ap) 00121 { 00122 int size; 00123 unsigned int tag; 00124 ByteIOContext *pb = s->pb; 00125 unsigned int id, channels, rate; 00126 enum CodecID codec; 00127 AVStream *st; 00128 00129 /* check ".snd" header */ 00130 tag = get_le32(pb); 00131 if (tag != MKTAG('.', 's', 'n', 'd')) 00132 return -1; 00133 size = get_be32(pb); /* header size */ 00134 get_be32(pb); /* data size */ 00135 00136 id = get_be32(pb); 00137 rate = get_be32(pb); 00138 channels = get_be32(pb); 00139 00140 codec = ff_codec_get_id(codec_au_tags, id); 00141 00142 if (size >= 24) { 00143 /* skip unused data */ 00144 url_fseek(pb, size - 24, SEEK_CUR); 00145 } 00146 00147 /* now we are ready: build format streams */ 00148 st = av_new_stream(s, 0); 00149 if (!st) 00150 return -1; 00151 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00152 st->codec->codec_tag = id; 00153 st->codec->codec_id = codec; 00154 st->codec->channels = channels; 00155 st->codec->sample_rate = rate; 00156 av_set_pts_info(st, 64, 1, rate); 00157 return 0; 00158 } 00159 00160 #define BLOCK_SIZE 1024 00161 00162 static int au_read_packet(AVFormatContext *s, 00163 AVPacket *pkt) 00164 { 00165 int ret; 00166 00167 ret= av_get_packet(s->pb, pkt, BLOCK_SIZE * 00168 s->streams[0]->codec->channels * 00169 av_get_bits_per_sample(s->streams[0]->codec->codec_id) >> 3); 00170 if (ret < 0) 00171 return ret; 00172 pkt->stream_index = 0; 00173 00174 /* note: we need to modify the packet size here to handle the last 00175 packet */ 00176 pkt->size = ret; 00177 return 0; 00178 } 00179 00180 #if CONFIG_AU_DEMUXER 00181 AVInputFormat au_demuxer = { 00182 "au", 00183 NULL_IF_CONFIG_SMALL("SUN AU format"), 00184 0, 00185 au_probe, 00186 au_read_header, 00187 au_read_packet, 00188 NULL, 00189 pcm_read_seek, 00190 .codec_tag= (const AVCodecTag* const []){codec_au_tags, 0}, 00191 }; 00192 #endif 00193 00194 #if CONFIG_AU_MUXER 00195 AVOutputFormat au_muxer = { 00196 "au", 00197 NULL_IF_CONFIG_SMALL("SUN AU format"), 00198 "audio/basic", 00199 "au", 00200 0, 00201 CODEC_ID_PCM_S16BE, 00202 CODEC_ID_NONE, 00203 au_write_header, 00204 au_write_packet, 00205 au_write_trailer, 00206 .codec_tag= (const AVCodecTag* const []){codec_au_tags, 0}, 00207 }; 00208 #endif //CONFIG_AU_MUXER