1/* 2 * AVS demuxer. 3 * Copyright (c) 2006 Aurelien Jacobs <aurel@gnuage.org> 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#include "avformat.h" 23#include "voc.h" 24 25 26typedef struct avs_format { 27 VocDecContext voc; 28 AVStream *st_video; 29 AVStream *st_audio; 30 int width; 31 int height; 32 int bits_per_sample; 33 int fps; 34 int nb_frames; 35 int remaining_frame_size; 36 int remaining_audio_size; 37} AvsFormat; 38 39typedef enum avs_block_type { 40 AVS_NONE = 0x00, 41 AVS_VIDEO = 0x01, 42 AVS_AUDIO = 0x02, 43 AVS_PALETTE = 0x03, 44 AVS_GAME_DATA = 0x04, 45} AvsBlockType; 46 47static int avs_probe(AVProbeData * p) 48{ 49 const uint8_t *d; 50 51 d = p->buf; 52 if (d[0] == 'w' && d[1] == 'W' && d[2] == 0x10 && d[3] == 0) 53 /* Ensure the buffer probe scores higher than the extension probe. 54 * This avoids problems with misdetection as AviSynth scripts. */ 55 return AVPROBE_SCORE_EXTENSION + 5; 56 57 return 0; 58} 59 60static int avs_read_header(AVFormatContext * s) 61{ 62 AvsFormat *avs = s->priv_data; 63 64 s->ctx_flags |= AVFMTCTX_NOHEADER; 65 66 avio_skip(s->pb, 4); 67 avs->width = avio_rl16(s->pb); 68 avs->height = avio_rl16(s->pb); 69 avs->bits_per_sample = avio_rl16(s->pb); 70 avs->fps = avio_rl16(s->pb); 71 avs->nb_frames = avio_rl32(s->pb); 72 avs->remaining_frame_size = 0; 73 avs->remaining_audio_size = 0; 74 75 avs->st_video = avs->st_audio = NULL; 76 77 if (avs->width != 318 || avs->height != 198) 78 av_log(s, AV_LOG_ERROR, "This avs pretend to be %dx%d " 79 "when the avs format is supposed to be 318x198 only.\n", 80 avs->width, avs->height); 81 82 return 0; 83} 84 85static int 86avs_read_video_packet(AVFormatContext * s, AVPacket * pkt, 87 AvsBlockType type, int sub_type, int size, 88 uint8_t * palette, int palette_size) 89{ 90 AvsFormat *avs = s->priv_data; 91 int ret; 92 93 ret = av_new_packet(pkt, size + palette_size); 94 if (ret < 0) 95 return ret; 96 97 if (palette_size) { 98 pkt->data[0] = 0x00; 99 pkt->data[1] = 0x03; 100 pkt->data[2] = palette_size & 0xFF; 101 pkt->data[3] = (palette_size >> 8) & 0xFF; 102 memcpy(pkt->data + 4, palette, palette_size - 4); 103 } 104 105 pkt->data[palette_size + 0] = sub_type; 106 pkt->data[palette_size + 1] = type; 107 pkt->data[palette_size + 2] = size & 0xFF; 108 pkt->data[palette_size + 3] = (size >> 8) & 0xFF; 109 ret = avio_read(s->pb, pkt->data + palette_size + 4, size - 4) + 4; 110 if (ret < size) { 111 av_free_packet(pkt); 112 return AVERROR(EIO); 113 } 114 115 pkt->size = ret + palette_size; 116 pkt->stream_index = avs->st_video->index; 117 if (sub_type == 0) 118 pkt->flags |= AV_PKT_FLAG_KEY; 119 120 return 0; 121} 122 123static int avs_read_audio_packet(AVFormatContext * s, AVPacket * pkt) 124{ 125 AvsFormat *avs = s->priv_data; 126 int ret, size; 127 128 size = avio_tell(s->pb); 129 ret = ff_voc_get_packet(s, pkt, avs->st_audio, avs->remaining_audio_size); 130 size = avio_tell(s->pb) - size; 131 avs->remaining_audio_size -= size; 132 133 if (ret == AVERROR(EIO)) 134 return 0; /* this indicate EOS */ 135 if (ret < 0) 136 return ret; 137 138 pkt->stream_index = avs->st_audio->index; 139 pkt->flags |= AV_PKT_FLAG_KEY; 140 141 return size; 142} 143 144static int avs_read_packet(AVFormatContext * s, AVPacket * pkt) 145{ 146 AvsFormat *avs = s->priv_data; 147 int sub_type = 0, size = 0; 148 AvsBlockType type = AVS_NONE; 149 int palette_size = 0; 150 uint8_t palette[4 + 3 * 256]; 151 int ret; 152 153 if (avs->remaining_audio_size > 0) 154 if (avs_read_audio_packet(s, pkt) > 0) 155 return 0; 156 157 while (1) { 158 if (avs->remaining_frame_size <= 0) { 159 if (!avio_rl16(s->pb)) /* found EOF */ 160 return AVERROR(EIO); 161 avs->remaining_frame_size = avio_rl16(s->pb) - 4; 162 } 163 164 while (avs->remaining_frame_size > 0) { 165 sub_type = avio_r8(s->pb); 166 type = avio_r8(s->pb); 167 size = avio_rl16(s->pb); 168 if (size < 4) 169 return AVERROR_INVALIDDATA; 170 avs->remaining_frame_size -= size; 171 172 switch (type) { 173 case AVS_PALETTE: 174 if (size - 4 > sizeof(palette)) 175 return AVERROR_INVALIDDATA; 176 ret = avio_read(s->pb, palette, size - 4); 177 if (ret < size - 4) 178 return AVERROR(EIO); 179 palette_size = size; 180 break; 181 182 case AVS_VIDEO: 183 if (!avs->st_video) { 184 avs->st_video = avformat_new_stream(s, NULL); 185 if (avs->st_video == NULL) 186 return AVERROR(ENOMEM); 187 avs->st_video->codec->codec_type = AVMEDIA_TYPE_VIDEO; 188 avs->st_video->codec->codec_id = AV_CODEC_ID_AVS; 189 avs->st_video->codec->width = avs->width; 190 avs->st_video->codec->height = avs->height; 191 avs->st_video->codec->bits_per_coded_sample=avs->bits_per_sample; 192 avs->st_video->nb_frames = avs->nb_frames; 193#if FF_API_R_FRAME_RATE 194 avs->st_video->r_frame_rate = 195#endif 196 avs->st_video->avg_frame_rate = (AVRational){avs->fps, 1}; 197 } 198 return avs_read_video_packet(s, pkt, type, sub_type, size, 199 palette, palette_size); 200 201 case AVS_AUDIO: 202 if (!avs->st_audio) { 203 avs->st_audio = avformat_new_stream(s, NULL); 204 if (avs->st_audio == NULL) 205 return AVERROR(ENOMEM); 206 avs->st_audio->codec->codec_type = AVMEDIA_TYPE_AUDIO; 207 } 208 avs->remaining_audio_size = size - 4; 209 size = avs_read_audio_packet(s, pkt); 210 if (size != 0) 211 return size; 212 break; 213 214 default: 215 avio_skip(s->pb, size - 4); 216 } 217 } 218 } 219} 220 221static int avs_read_close(AVFormatContext * s) 222{ 223 return 0; 224} 225 226AVInputFormat ff_avs_demuxer = { 227 .name = "avs", 228 .long_name = NULL_IF_CONFIG_SMALL("AVS"), 229 .priv_data_size = sizeof(AvsFormat), 230 .read_probe = avs_probe, 231 .read_header = avs_read_header, 232 .read_packet = avs_read_packet, 233 .read_close = avs_read_close, 234}; 235