1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Beam Software SIFF demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2007 Konstantin Shishkov 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h" 23cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "avformat.h" 26cabdff1aSopenharmony_ci#include "internal.h" 27cabdff1aSopenharmony_ci#include "avio_internal.h" 28cabdff1aSopenharmony_ci 29cabdff1aSopenharmony_cienum SIFFTags { 30cabdff1aSopenharmony_ci TAG_SIFF = MKTAG('S', 'I', 'F', 'F'), 31cabdff1aSopenharmony_ci TAG_BODY = MKTAG('B', 'O', 'D', 'Y'), 32cabdff1aSopenharmony_ci TAG_VBHD = MKTAG('V', 'B', 'H', 'D'), 33cabdff1aSopenharmony_ci TAG_SHDR = MKTAG('S', 'H', 'D', 'R'), 34cabdff1aSopenharmony_ci TAG_VBV1 = MKTAG('V', 'B', 'V', '1'), 35cabdff1aSopenharmony_ci TAG_SOUN = MKTAG('S', 'O', 'U', 'N'), 36cabdff1aSopenharmony_ci}; 37cabdff1aSopenharmony_ci 38cabdff1aSopenharmony_cienum VBFlags { 39cabdff1aSopenharmony_ci VB_HAS_GMC = 0x01, 40cabdff1aSopenharmony_ci VB_HAS_AUDIO = 0x04, 41cabdff1aSopenharmony_ci VB_HAS_VIDEO = 0x08, 42cabdff1aSopenharmony_ci VB_HAS_PALETTE = 0x10, 43cabdff1aSopenharmony_ci VB_HAS_LENGTH = 0x20 44cabdff1aSopenharmony_ci}; 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_citypedef struct SIFFContext { 47cabdff1aSopenharmony_ci int frames; 48cabdff1aSopenharmony_ci int cur_frame; 49cabdff1aSopenharmony_ci int rate; 50cabdff1aSopenharmony_ci int bits; 51cabdff1aSopenharmony_ci int block_align; 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci int has_video; 54cabdff1aSopenharmony_ci int has_audio; 55cabdff1aSopenharmony_ci 56cabdff1aSopenharmony_ci int curstrm; 57cabdff1aSopenharmony_ci unsigned int pktsize; 58cabdff1aSopenharmony_ci int gmcsize; 59cabdff1aSopenharmony_ci unsigned int sndsize; 60cabdff1aSopenharmony_ci 61cabdff1aSopenharmony_ci unsigned int flags; 62cabdff1aSopenharmony_ci uint8_t gmc[4]; 63cabdff1aSopenharmony_ci} SIFFContext; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_cistatic int siff_probe(const AVProbeData *p) 66cabdff1aSopenharmony_ci{ 67cabdff1aSopenharmony_ci uint32_t tag = AV_RL32(p->buf + 8); 68cabdff1aSopenharmony_ci /* check file header */ 69cabdff1aSopenharmony_ci if (AV_RL32(p->buf) != TAG_SIFF || 70cabdff1aSopenharmony_ci (tag != TAG_VBV1 && tag != TAG_SOUN)) 71cabdff1aSopenharmony_ci return 0; 72cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 73cabdff1aSopenharmony_ci} 74cabdff1aSopenharmony_ci 75cabdff1aSopenharmony_cistatic int create_audio_stream(AVFormatContext *s, SIFFContext *c) 76cabdff1aSopenharmony_ci{ 77cabdff1aSopenharmony_ci AVStream *ast; 78cabdff1aSopenharmony_ci ast = avformat_new_stream(s, NULL); 79cabdff1aSopenharmony_ci if (!ast) 80cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 81cabdff1aSopenharmony_ci ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 82cabdff1aSopenharmony_ci ast->codecpar->codec_id = AV_CODEC_ID_PCM_U8; 83cabdff1aSopenharmony_ci ast->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; 84cabdff1aSopenharmony_ci ast->codecpar->bits_per_coded_sample = 8; 85cabdff1aSopenharmony_ci ast->codecpar->sample_rate = c->rate; 86cabdff1aSopenharmony_ci avpriv_set_pts_info(ast, 16, 1, c->rate); 87cabdff1aSopenharmony_ci ast->start_time = 0; 88cabdff1aSopenharmony_ci return 0; 89cabdff1aSopenharmony_ci} 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_cistatic int siff_parse_vbv1(AVFormatContext *s, SIFFContext *c, AVIOContext *pb) 92cabdff1aSopenharmony_ci{ 93cabdff1aSopenharmony_ci AVStream *st; 94cabdff1aSopenharmony_ci int width, height; 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci if (avio_rl32(pb) != TAG_VBHD) { 97cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Header chunk is missing\n"); 98cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 99cabdff1aSopenharmony_ci } 100cabdff1aSopenharmony_ci if (avio_rb32(pb) != 32) { 101cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n"); 102cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 103cabdff1aSopenharmony_ci } 104cabdff1aSopenharmony_ci if (avio_rl16(pb) != 1) { 105cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Incorrect header version\n"); 106cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 107cabdff1aSopenharmony_ci } 108cabdff1aSopenharmony_ci width = avio_rl16(pb); 109cabdff1aSopenharmony_ci height = avio_rl16(pb); 110cabdff1aSopenharmony_ci avio_skip(pb, 4); 111cabdff1aSopenharmony_ci c->frames = avio_rl16(pb); 112cabdff1aSopenharmony_ci if (!c->frames) { 113cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "File contains no frames ???\n"); 114cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 115cabdff1aSopenharmony_ci } 116cabdff1aSopenharmony_ci c->bits = avio_rl16(pb); 117cabdff1aSopenharmony_ci c->rate = avio_rl16(pb); 118cabdff1aSopenharmony_ci c->block_align = c->rate * (c->bits >> 3); 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci avio_skip(pb, 16); // zeroes 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 123cabdff1aSopenharmony_ci if (!st) 124cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 125cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 126cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_VB; 127cabdff1aSopenharmony_ci st->codecpar->codec_tag = MKTAG('V', 'B', 'V', '1'); 128cabdff1aSopenharmony_ci st->codecpar->width = width; 129cabdff1aSopenharmony_ci st->codecpar->height = height; 130cabdff1aSopenharmony_ci st->codecpar->format = AV_PIX_FMT_PAL8; 131cabdff1aSopenharmony_ci st->nb_frames = 132cabdff1aSopenharmony_ci st->duration = c->frames; 133cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 16, 1, 12); 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci c->cur_frame = 0; 136cabdff1aSopenharmony_ci c->has_video = 1; 137cabdff1aSopenharmony_ci c->has_audio = !!c->rate; 138cabdff1aSopenharmony_ci c->curstrm = -1; 139cabdff1aSopenharmony_ci if (c->has_audio) 140cabdff1aSopenharmony_ci return create_audio_stream(s, c); 141cabdff1aSopenharmony_ci return 0; 142cabdff1aSopenharmony_ci} 143cabdff1aSopenharmony_ci 144cabdff1aSopenharmony_cistatic int siff_parse_soun(AVFormatContext *s, SIFFContext *c, AVIOContext *pb) 145cabdff1aSopenharmony_ci{ 146cabdff1aSopenharmony_ci if (avio_rl32(pb) != TAG_SHDR) { 147cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Header chunk is missing\n"); 148cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 149cabdff1aSopenharmony_ci } 150cabdff1aSopenharmony_ci if (avio_rb32(pb) != 8) { 151cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Header chunk size is incorrect\n"); 152cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 153cabdff1aSopenharmony_ci } 154cabdff1aSopenharmony_ci avio_skip(pb, 4); // unknown value 155cabdff1aSopenharmony_ci c->rate = avio_rl16(pb); 156cabdff1aSopenharmony_ci c->bits = avio_rl16(pb); 157cabdff1aSopenharmony_ci c->block_align = c->rate * (c->bits >> 3); 158cabdff1aSopenharmony_ci return create_audio_stream(s, c); 159cabdff1aSopenharmony_ci} 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_cistatic int siff_read_header(AVFormatContext *s) 162cabdff1aSopenharmony_ci{ 163cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 164cabdff1aSopenharmony_ci SIFFContext *c = s->priv_data; 165cabdff1aSopenharmony_ci uint32_t tag; 166cabdff1aSopenharmony_ci int ret; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci if (avio_rl32(pb) != TAG_SIFF) 169cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 170cabdff1aSopenharmony_ci avio_skip(pb, 4); // ignore size 171cabdff1aSopenharmony_ci tag = avio_rl32(pb); 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci if (tag != TAG_VBV1 && tag != TAG_SOUN) { 174cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "Not a VBV file\n"); 175cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 176cabdff1aSopenharmony_ci } 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_ci if (tag == TAG_VBV1 && (ret = siff_parse_vbv1(s, c, pb)) < 0) 179cabdff1aSopenharmony_ci return ret; 180cabdff1aSopenharmony_ci if (tag == TAG_SOUN && (ret = siff_parse_soun(s, c, pb)) < 0) 181cabdff1aSopenharmony_ci return ret; 182cabdff1aSopenharmony_ci if (avio_rl32(pb) != MKTAG('B', 'O', 'D', 'Y')) { 183cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "'BODY' chunk is missing\n"); 184cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 185cabdff1aSopenharmony_ci } 186cabdff1aSopenharmony_ci avio_skip(pb, 4); // ignore size 187cabdff1aSopenharmony_ci 188cabdff1aSopenharmony_ci return 0; 189cabdff1aSopenharmony_ci} 190cabdff1aSopenharmony_ci 191cabdff1aSopenharmony_cistatic int siff_read_packet(AVFormatContext *s, AVPacket *pkt) 192cabdff1aSopenharmony_ci{ 193cabdff1aSopenharmony_ci SIFFContext *c = s->priv_data; 194cabdff1aSopenharmony_ci int ret; 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_ci if (c->has_video) { 197cabdff1aSopenharmony_ci unsigned int size; 198cabdff1aSopenharmony_ci if (c->cur_frame >= c->frames) 199cabdff1aSopenharmony_ci return AVERROR_EOF; 200cabdff1aSopenharmony_ci if (c->curstrm == -1) { 201cabdff1aSopenharmony_ci c->pktsize = avio_rl32(s->pb) - 4; 202cabdff1aSopenharmony_ci c->flags = avio_rl16(s->pb); 203cabdff1aSopenharmony_ci if (c->flags & VB_HAS_AUDIO && !c->has_audio) 204cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 205cabdff1aSopenharmony_ci c->gmcsize = (c->flags & VB_HAS_GMC) ? 4 : 0; 206cabdff1aSopenharmony_ci if (c->gmcsize) 207cabdff1aSopenharmony_ci avio_read(s->pb, c->gmc, c->gmcsize); 208cabdff1aSopenharmony_ci c->sndsize = (c->flags & VB_HAS_AUDIO) ? avio_rl32(s->pb) : 0; 209cabdff1aSopenharmony_ci c->curstrm = !!(c->flags & VB_HAS_AUDIO); 210cabdff1aSopenharmony_ci } 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_ci if (!c->curstrm) { 213cabdff1aSopenharmony_ci if (c->pktsize < 2LL + c->sndsize + c->gmcsize) 214cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 215cabdff1aSopenharmony_ci 216cabdff1aSopenharmony_ci size = c->pktsize - c->sndsize - c->gmcsize - 2; 217cabdff1aSopenharmony_ci size = ffio_limit(s->pb, size); 218cabdff1aSopenharmony_ci if ((ret = av_new_packet(pkt, size + c->gmcsize + 2)) < 0) 219cabdff1aSopenharmony_ci return ret; 220cabdff1aSopenharmony_ci AV_WL16(pkt->data, c->flags); 221cabdff1aSopenharmony_ci if (c->gmcsize) 222cabdff1aSopenharmony_ci memcpy(pkt->data + 2, c->gmc, c->gmcsize); 223cabdff1aSopenharmony_ci if (avio_read(s->pb, pkt->data + 2 + c->gmcsize, size) != size) { 224cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 225cabdff1aSopenharmony_ci } 226cabdff1aSopenharmony_ci pkt->stream_index = 0; 227cabdff1aSopenharmony_ci c->curstrm = -1; 228cabdff1aSopenharmony_ci } else { 229cabdff1aSopenharmony_ci int pktsize = av_get_packet(s->pb, pkt, c->sndsize - 4); 230cabdff1aSopenharmony_ci if (pktsize < 0) 231cabdff1aSopenharmony_ci return AVERROR(EIO); 232cabdff1aSopenharmony_ci pkt->stream_index = 1; 233cabdff1aSopenharmony_ci pkt->duration = pktsize; 234cabdff1aSopenharmony_ci c->curstrm = 0; 235cabdff1aSopenharmony_ci } 236cabdff1aSopenharmony_ci if (!c->cur_frame || c->curstrm) 237cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 238cabdff1aSopenharmony_ci if (c->curstrm == -1) 239cabdff1aSopenharmony_ci c->cur_frame++; 240cabdff1aSopenharmony_ci } else { 241cabdff1aSopenharmony_ci int pktsize = av_get_packet(s->pb, pkt, c->block_align); 242cabdff1aSopenharmony_ci if (!pktsize) 243cabdff1aSopenharmony_ci return AVERROR_EOF; 244cabdff1aSopenharmony_ci if (pktsize <= 0) 245cabdff1aSopenharmony_ci return AVERROR(EIO); 246cabdff1aSopenharmony_ci pkt->duration = pktsize; 247cabdff1aSopenharmony_ci } 248cabdff1aSopenharmony_ci return pkt->size; 249cabdff1aSopenharmony_ci} 250cabdff1aSopenharmony_ci 251cabdff1aSopenharmony_ciconst AVInputFormat ff_siff_demuxer = { 252cabdff1aSopenharmony_ci .name = "siff", 253cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Beam Software SIFF"), 254cabdff1aSopenharmony_ci .priv_data_size = sizeof(SIFFContext), 255cabdff1aSopenharmony_ci .read_probe = siff_probe, 256cabdff1aSopenharmony_ci .read_header = siff_read_header, 257cabdff1aSopenharmony_ci .read_packet = siff_read_packet, 258cabdff1aSopenharmony_ci .extensions = "vb,son", 259cabdff1aSopenharmony_ci}; 260