00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "avformat.h"
00031 #include "internal.h"
00032 #include "avio_internal.h"
00033 #include "pcm.h"
00034
00035
00036 #define AU_UNKNOWN_SIZE ((uint32_t)(~0))
00037
00038 #define AU_HEADER_SIZE (24+8)
00039
00040
00041 static const AVCodecTag codec_au_tags[] = {
00042 { AV_CODEC_ID_PCM_MULAW, 1 },
00043 { AV_CODEC_ID_PCM_S8, 2 },
00044 { AV_CODEC_ID_PCM_S16BE, 3 },
00045 { AV_CODEC_ID_PCM_S24BE, 4 },
00046 { AV_CODEC_ID_PCM_S32BE, 5 },
00047 { AV_CODEC_ID_PCM_F32BE, 6 },
00048 { AV_CODEC_ID_PCM_F64BE, 7 },
00049 { AV_CODEC_ID_ADPCM_G722, 24 },
00050 { AV_CODEC_ID_PCM_ALAW, 27 },
00051 { AV_CODEC_ID_NONE, 0 },
00052 };
00053
00054 #if CONFIG_AU_MUXER
00055
00056 static int put_au_header(AVIOContext *pb, AVCodecContext *enc)
00057 {
00058 if(!enc->codec_tag)
00059 return -1;
00060 ffio_wfourcc(pb, ".snd");
00061 avio_wb32(pb, AU_HEADER_SIZE);
00062 avio_wb32(pb, AU_UNKNOWN_SIZE);
00063 avio_wb32(pb, (uint32_t)enc->codec_tag);
00064 avio_wb32(pb, enc->sample_rate);
00065 avio_wb32(pb, (uint32_t)enc->channels);
00066 avio_wb64(pb, 0);
00067 return 0;
00068 }
00069
00070 static int au_write_header(AVFormatContext *s)
00071 {
00072 AVIOContext *pb = s->pb;
00073
00074
00075 if (put_au_header(pb, s->streams[0]->codec) < 0) {
00076 return -1;
00077 }
00078
00079 avio_flush(pb);
00080
00081 return 0;
00082 }
00083
00084 static int au_write_packet(AVFormatContext *s, AVPacket *pkt)
00085 {
00086 AVIOContext *pb = s->pb;
00087 avio_write(pb, pkt->data, pkt->size);
00088 return 0;
00089 }
00090
00091 static int au_write_trailer(AVFormatContext *s)
00092 {
00093 AVIOContext *pb = s->pb;
00094 int64_t file_size;
00095
00096 if (s->pb->seekable) {
00097
00098
00099 file_size = avio_tell(pb);
00100 avio_seek(pb, 8, SEEK_SET);
00101 avio_wb32(pb, (uint32_t)(file_size - AU_HEADER_SIZE));
00102 avio_seek(pb, file_size, SEEK_SET);
00103
00104 avio_flush(pb);
00105 }
00106
00107 return 0;
00108 }
00109 #endif
00110
00111 static int au_probe(AVProbeData *p)
00112 {
00113
00114 if (p->buf[0] == '.' && p->buf[1] == 's' &&
00115 p->buf[2] == 'n' && p->buf[3] == 'd')
00116 return AVPROBE_SCORE_MAX;
00117 else
00118 return 0;
00119 }
00120
00121
00122 static int au_read_header(AVFormatContext *s)
00123 {
00124 int size, bps, data_size = 0;
00125 unsigned int tag;
00126 AVIOContext *pb = s->pb;
00127 unsigned int id, channels, rate;
00128 enum AVCodecID codec;
00129 AVStream *st;
00130
00131
00132 tag = avio_rl32(pb);
00133 if (tag != MKTAG('.', 's', 'n', 'd'))
00134 return -1;
00135 size = avio_rb32(pb);
00136 data_size = avio_rb32(pb);
00137
00138 if (data_size < 0 && data_size != AU_UNKNOWN_SIZE) {
00139 av_log(s, AV_LOG_ERROR, "Invalid negative data size '%d' found\n", data_size);
00140 return AVERROR_INVALIDDATA;
00141 }
00142
00143 id = avio_rb32(pb);
00144 rate = avio_rb32(pb);
00145 channels = avio_rb32(pb);
00146
00147 codec = ff_codec_get_id(codec_au_tags, id);
00148
00149 if (!(bps = av_get_bits_per_sample(codec))) {
00150 av_log_ask_for_sample(s, "could not determine bits per sample\n");
00151 return AVERROR_INVALIDDATA;
00152 }
00153
00154 if (channels == 0 || channels > 64) {
00155 av_log(s, AV_LOG_ERROR, "Invalid number of channels %d\n", channels);
00156 return AVERROR_INVALIDDATA;
00157 }
00158
00159 if (size >= 24) {
00160
00161 avio_skip(pb, size - 24);
00162 }
00163
00164
00165 st = avformat_new_stream(s, NULL);
00166 if (!st)
00167 return -1;
00168 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00169 st->codec->codec_tag = id;
00170 st->codec->codec_id = codec;
00171 st->codec->channels = channels;
00172 st->codec->sample_rate = rate;
00173 st->codec->block_align = FFMAX(bps * st->codec->channels / 8, 1);
00174 if (data_size != AU_UNKNOWN_SIZE)
00175 st->duration = (((int64_t)data_size)<<3) / (st->codec->channels * (int64_t)bps);
00176 avpriv_set_pts_info(st, 64, 1, rate);
00177 return 0;
00178 }
00179
00180 #if CONFIG_AU_DEMUXER
00181 AVInputFormat ff_au_demuxer = {
00182 .name = "au",
00183 .long_name = NULL_IF_CONFIG_SMALL("Sun AU"),
00184 .read_probe = au_probe,
00185 .read_header = au_read_header,
00186 .read_packet = ff_pcm_read_packet,
00187 .read_seek = ff_pcm_read_seek,
00188 .codec_tag = (const AVCodecTag* const []){ codec_au_tags, 0 },
00189 };
00190 #endif
00191
00192 #if CONFIG_AU_MUXER
00193 AVOutputFormat ff_au_muxer = {
00194 .name = "au",
00195 .long_name = NULL_IF_CONFIG_SMALL("Sun AU"),
00196 .mime_type = "audio/basic",
00197 .extensions = "au",
00198 .audio_codec = AV_CODEC_ID_PCM_S16BE,
00199 .video_codec = AV_CODEC_ID_NONE,
00200 .write_header = au_write_header,
00201 .write_packet = au_write_packet,
00202 .write_trailer = au_write_trailer,
00203 .codec_tag = (const AVCodecTag* const []){ codec_au_tags, 0 },
00204 };
00205 #endif //CONFIG_AU_MUXER