1/* 2 * Sierra SOL demuxer 3 * Copyright Konstantin Shishkov 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/* 23 * Based on documents from Game Audio Player and own research 24 */ 25 26#include "libavutil/bswap.h" 27#include "avformat.h" 28#include "raw.h" 29 30/* if we don't know the size in advance */ 31#define AU_UNKNOWN_SIZE ((uint32_t)(~0)) 32 33static int sol_probe(AVProbeData *p) 34{ 35 /* check file header */ 36 uint16_t magic; 37 magic=le2me_16(*((uint16_t*)p->buf)); 38 if ((magic == 0x0B8D || magic == 0x0C0D || magic == 0x0C8D) && 39 p->buf[2] == 'S' && p->buf[3] == 'O' && 40 p->buf[4] == 'L' && p->buf[5] == 0) 41 return AVPROBE_SCORE_MAX; 42 else 43 return 0; 44} 45 46#define SOL_DPCM 1 47#define SOL_16BIT 4 48#define SOL_STEREO 16 49 50static enum CodecID sol_codec_id(int magic, int type) 51{ 52 if (magic == 0x0B8D) 53 { 54 if (type & SOL_DPCM) return CODEC_ID_SOL_DPCM; 55 else return CODEC_ID_PCM_U8; 56 } 57 if (type & SOL_DPCM) 58 { 59 if (type & SOL_16BIT) return CODEC_ID_SOL_DPCM; 60 else if (magic == 0x0C8D) return CODEC_ID_SOL_DPCM; 61 else return CODEC_ID_SOL_DPCM; 62 } 63 if (type & SOL_16BIT) return CODEC_ID_PCM_S16LE; 64 return CODEC_ID_PCM_U8; 65} 66 67static int sol_codec_type(int magic, int type) 68{ 69 if (magic == 0x0B8D) return 1;//SOL_DPCM_OLD; 70 if (type & SOL_DPCM) 71 { 72 if (type & SOL_16BIT) return 3;//SOL_DPCM_NEW16; 73 else if (magic == 0x0C8D) return 1;//SOL_DPCM_OLD; 74 else return 2;//SOL_DPCM_NEW8; 75 } 76 return -1; 77} 78 79static int sol_channels(int magic, int type) 80{ 81 if (magic == 0x0B8D || !(type & SOL_STEREO)) return 1; 82 return 2; 83} 84 85static int sol_read_header(AVFormatContext *s, 86 AVFormatParameters *ap) 87{ 88 int size; 89 unsigned int magic,tag; 90 ByteIOContext *pb = s->pb; 91 unsigned int id, channels, rate, type; 92 enum CodecID codec; 93 AVStream *st; 94 95 /* check ".snd" header */ 96 magic = get_le16(pb); 97 tag = get_le32(pb); 98 if (tag != MKTAG('S', 'O', 'L', 0)) 99 return -1; 100 rate = get_le16(pb); 101 type = get_byte(pb); 102 size = get_le32(pb); 103 if (magic != 0x0B8D) 104 get_byte(pb); /* newer SOLs contain padding byte */ 105 106 codec = sol_codec_id(magic, type); 107 channels = sol_channels(magic, type); 108 109 if (codec == CODEC_ID_SOL_DPCM) 110 id = sol_codec_type(magic, type); 111 else id = 0; 112 113 /* now we are ready: build format streams */ 114 st = av_new_stream(s, 0); 115 if (!st) 116 return -1; 117 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 118 st->codec->codec_tag = id; 119 st->codec->codec_id = codec; 120 st->codec->channels = channels; 121 st->codec->sample_rate = rate; 122 av_set_pts_info(st, 64, 1, rate); 123 return 0; 124} 125 126#define MAX_SIZE 4096 127 128static int sol_read_packet(AVFormatContext *s, 129 AVPacket *pkt) 130{ 131 int ret; 132 133 if (url_feof(s->pb)) 134 return AVERROR(EIO); 135 ret= av_get_packet(s->pb, pkt, MAX_SIZE); 136 pkt->stream_index = 0; 137 138 /* note: we need to modify the packet size here to handle the last 139 packet */ 140 pkt->size = ret; 141 return 0; 142} 143 144AVInputFormat sol_demuxer = { 145 "sol", 146 NULL_IF_CONFIG_SMALL("Sierra SOL format"), 147 0, 148 sol_probe, 149 sol_read_header, 150 sol_read_packet, 151 NULL, 152 pcm_read_seek, 153}; 154