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 #include "libavutil/intreadwrite.h"
00027 #include "avformat.h"
00028 #include "internal.h"
00029 #include "pcm.h"
00030
00031
00032 #define AU_UNKNOWN_SIZE ((uint32_t)(~0))
00033
00034 static int sol_probe(AVProbeData *p)
00035 {
00036
00037 uint16_t magic = AV_RL32(p->buf);
00038 if ((magic == 0x0B8D || magic == 0x0C0D || magic == 0x0C8D) &&
00039 p->buf[2] == 'S' && p->buf[3] == 'O' &&
00040 p->buf[4] == 'L' && p->buf[5] == 0)
00041 return AVPROBE_SCORE_MAX;
00042 else
00043 return 0;
00044 }
00045
00046 #define SOL_DPCM 1
00047 #define SOL_16BIT 4
00048 #define SOL_STEREO 16
00049
00050 static enum AVCodecID sol_codec_id(int magic, int type)
00051 {
00052 if (magic == 0x0B8D)
00053 {
00054 if (type & SOL_DPCM) return AV_CODEC_ID_SOL_DPCM;
00055 else return AV_CODEC_ID_PCM_U8;
00056 }
00057 if (type & SOL_DPCM)
00058 {
00059 if (type & SOL_16BIT) return AV_CODEC_ID_SOL_DPCM;
00060 else if (magic == 0x0C8D) return AV_CODEC_ID_SOL_DPCM;
00061 else return AV_CODEC_ID_SOL_DPCM;
00062 }
00063 if (type & SOL_16BIT) return AV_CODEC_ID_PCM_S16LE;
00064 return AV_CODEC_ID_PCM_U8;
00065 }
00066
00067 static int sol_codec_type(int magic, int type)
00068 {
00069 if (magic == 0x0B8D) return 1;
00070 if (type & SOL_DPCM)
00071 {
00072 if (type & SOL_16BIT) return 3;
00073 else if (magic == 0x0C8D) return 1;
00074 else return 2;
00075 }
00076 return -1;
00077 }
00078
00079 static int sol_channels(int magic, int type)
00080 {
00081 if (magic == 0x0B8D || !(type & SOL_STEREO)) return 1;
00082 return 2;
00083 }
00084
00085 static int sol_read_header(AVFormatContext *s)
00086 {
00087 unsigned int magic,tag;
00088 AVIOContext *pb = s->pb;
00089 unsigned int id, channels, rate, type;
00090 enum AVCodecID codec;
00091 AVStream *st;
00092
00093
00094 magic = avio_rl16(pb);
00095 tag = avio_rl32(pb);
00096 if (tag != MKTAG('S', 'O', 'L', 0))
00097 return -1;
00098 rate = avio_rl16(pb);
00099 type = avio_r8(pb);
00100 avio_skip(pb, 4);
00101 if (magic != 0x0B8D)
00102 avio_r8(pb);
00103
00104 codec = sol_codec_id(magic, type);
00105 channels = sol_channels(magic, type);
00106
00107 if (codec == AV_CODEC_ID_SOL_DPCM)
00108 id = sol_codec_type(magic, type);
00109 else id = 0;
00110
00111
00112 st = avformat_new_stream(s, NULL);
00113 if (!st)
00114 return -1;
00115 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00116 st->codec->codec_tag = id;
00117 st->codec->codec_id = codec;
00118 st->codec->channels = channels;
00119 st->codec->sample_rate = rate;
00120 avpriv_set_pts_info(st, 64, 1, rate);
00121 return 0;
00122 }
00123
00124 #define MAX_SIZE 4096
00125
00126 static int sol_read_packet(AVFormatContext *s,
00127 AVPacket *pkt)
00128 {
00129 int ret;
00130
00131 if (url_feof(s->pb))
00132 return AVERROR(EIO);
00133 ret= av_get_packet(s->pb, pkt, MAX_SIZE);
00134 if (ret < 0)
00135 return ret;
00136 pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
00137 pkt->stream_index = 0;
00138 return 0;
00139 }
00140
00141 AVInputFormat ff_sol_demuxer = {
00142 .name = "sol",
00143 .long_name = NULL_IF_CONFIG_SMALL("Sierra SOL"),
00144 .read_probe = sol_probe,
00145 .read_header = sol_read_header,
00146 .read_packet = sol_read_packet,
00147 .read_seek = ff_pcm_read_seek,
00148 };