1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * id RoQ (.roq) File Demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2003 The FFmpeg project 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/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * id RoQ format file demuxer 25cabdff1aSopenharmony_ci * by Mike Melanson (melanson@pcisys.net) 26cabdff1aSopenharmony_ci * for more information on the .roq file format, visit: 27cabdff1aSopenharmony_ci * http://www.csse.monash.edu.au/~timf/ 28cabdff1aSopenharmony_ci */ 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h" 31cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 32cabdff1aSopenharmony_ci#include "avformat.h" 33cabdff1aSopenharmony_ci#include "internal.h" 34cabdff1aSopenharmony_ci#include "avio_internal.h" 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_ci#define RoQ_MAGIC_NUMBER 0x1084 37cabdff1aSopenharmony_ci#define RoQ_CHUNK_PREAMBLE_SIZE 8 38cabdff1aSopenharmony_ci#define RoQ_AUDIO_SAMPLE_RATE 22050 39cabdff1aSopenharmony_ci#define RoQ_CHUNKS_TO_SCAN 30 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_ci#define RoQ_INFO 0x1001 42cabdff1aSopenharmony_ci#define RoQ_QUAD_CODEBOOK 0x1002 43cabdff1aSopenharmony_ci#define RoQ_QUAD_VQ 0x1011 44cabdff1aSopenharmony_ci#define RoQ_SOUND_MONO 0x1020 45cabdff1aSopenharmony_ci#define RoQ_SOUND_STEREO 0x1021 46cabdff1aSopenharmony_ci 47cabdff1aSopenharmony_citypedef struct RoqDemuxContext { 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_ci int frame_rate; 50cabdff1aSopenharmony_ci int width; 51cabdff1aSopenharmony_ci int height; 52cabdff1aSopenharmony_ci int audio_channels; 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci int video_stream_index; 55cabdff1aSopenharmony_ci int audio_stream_index; 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_ci int64_t video_pts; 58cabdff1aSopenharmony_ci unsigned int audio_frame_count; 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci} RoqDemuxContext; 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_cistatic int roq_probe(const AVProbeData *p) 63cabdff1aSopenharmony_ci{ 64cabdff1aSopenharmony_ci if ((AV_RL16(&p->buf[0]) != RoQ_MAGIC_NUMBER) || 65cabdff1aSopenharmony_ci (AV_RL32(&p->buf[2]) != 0xFFFFFFFF)) 66cabdff1aSopenharmony_ci return 0; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 69cabdff1aSopenharmony_ci} 70cabdff1aSopenharmony_ci 71cabdff1aSopenharmony_cistatic int roq_read_header(AVFormatContext *s) 72cabdff1aSopenharmony_ci{ 73cabdff1aSopenharmony_ci RoqDemuxContext *roq = s->priv_data; 74cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 75cabdff1aSopenharmony_ci unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci /* get the main header */ 78cabdff1aSopenharmony_ci if (avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != 79cabdff1aSopenharmony_ci RoQ_CHUNK_PREAMBLE_SIZE) 80cabdff1aSopenharmony_ci return AVERROR(EIO); 81cabdff1aSopenharmony_ci roq->frame_rate = AV_RL16(&preamble[6]); 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_ci /* init private context parameters */ 84cabdff1aSopenharmony_ci roq->width = roq->height = roq->audio_channels = roq->video_pts = 85cabdff1aSopenharmony_ci roq->audio_frame_count = 0; 86cabdff1aSopenharmony_ci roq->audio_stream_index = -1; 87cabdff1aSopenharmony_ci roq->video_stream_index = -1; 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci s->ctx_flags |= AVFMTCTX_NOHEADER; 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci return 0; 92cabdff1aSopenharmony_ci} 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_cistatic int roq_read_packet(AVFormatContext *s, 95cabdff1aSopenharmony_ci AVPacket *pkt) 96cabdff1aSopenharmony_ci{ 97cabdff1aSopenharmony_ci RoqDemuxContext *roq = s->priv_data; 98cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 99cabdff1aSopenharmony_ci int ret = 0; 100cabdff1aSopenharmony_ci unsigned int chunk_size; 101cabdff1aSopenharmony_ci unsigned int chunk_type; 102cabdff1aSopenharmony_ci unsigned int codebook_size; 103cabdff1aSopenharmony_ci unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; 104cabdff1aSopenharmony_ci int packet_read = 0; 105cabdff1aSopenharmony_ci int64_t codebook_offset; 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_ci while (!packet_read) { 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci if (avio_feof(s->pb)) 110cabdff1aSopenharmony_ci return AVERROR(EIO); 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci /* get the next chunk preamble */ 113cabdff1aSopenharmony_ci if ((ret = avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE)) != 114cabdff1aSopenharmony_ci RoQ_CHUNK_PREAMBLE_SIZE) 115cabdff1aSopenharmony_ci return AVERROR(EIO); 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci chunk_type = AV_RL16(&preamble[0]); 118cabdff1aSopenharmony_ci chunk_size = AV_RL32(&preamble[2]); 119cabdff1aSopenharmony_ci if(chunk_size > INT_MAX) 120cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_ci chunk_size = ffio_limit(pb, chunk_size); 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci switch (chunk_type) { 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci case RoQ_INFO: 127cabdff1aSopenharmony_ci if (roq->video_stream_index == -1) { 128cabdff1aSopenharmony_ci AVStream *st = avformat_new_stream(s, NULL); 129cabdff1aSopenharmony_ci if (!st) 130cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 131cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 63, 1, roq->frame_rate); 132cabdff1aSopenharmony_ci roq->video_stream_index = st->index; 133cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 134cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_ROQ; 135cabdff1aSopenharmony_ci st->codecpar->codec_tag = 0; /* no fourcc */ 136cabdff1aSopenharmony_ci 137cabdff1aSopenharmony_ci if (avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != RoQ_CHUNK_PREAMBLE_SIZE) 138cabdff1aSopenharmony_ci return AVERROR(EIO); 139cabdff1aSopenharmony_ci st->codecpar->width = roq->width = AV_RL16(preamble); 140cabdff1aSopenharmony_ci st->codecpar->height = roq->height = AV_RL16(preamble + 2); 141cabdff1aSopenharmony_ci break; 142cabdff1aSopenharmony_ci } 143cabdff1aSopenharmony_ci /* don't care about this chunk anymore */ 144cabdff1aSopenharmony_ci avio_skip(pb, RoQ_CHUNK_PREAMBLE_SIZE); 145cabdff1aSopenharmony_ci break; 146cabdff1aSopenharmony_ci 147cabdff1aSopenharmony_ci case RoQ_QUAD_CODEBOOK: 148cabdff1aSopenharmony_ci if (roq->video_stream_index < 0) 149cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 150cabdff1aSopenharmony_ci /* packet needs to contain both this codebook and next VQ chunk */ 151cabdff1aSopenharmony_ci codebook_offset = avio_tell(pb) - RoQ_CHUNK_PREAMBLE_SIZE; 152cabdff1aSopenharmony_ci codebook_size = chunk_size; 153cabdff1aSopenharmony_ci avio_skip(pb, codebook_size); 154cabdff1aSopenharmony_ci if (avio_read(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != 155cabdff1aSopenharmony_ci RoQ_CHUNK_PREAMBLE_SIZE) 156cabdff1aSopenharmony_ci return AVERROR(EIO); 157cabdff1aSopenharmony_ci chunk_size = AV_RL32(&preamble[2]) + RoQ_CHUNK_PREAMBLE_SIZE * 2 + 158cabdff1aSopenharmony_ci codebook_size; 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_ci if (chunk_size > INT_MAX) 161cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci /* rewind */ 164cabdff1aSopenharmony_ci avio_seek(pb, codebook_offset, SEEK_SET); 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci /* load up the packet */ 167cabdff1aSopenharmony_ci ret= av_get_packet(pb, pkt, chunk_size); 168cabdff1aSopenharmony_ci if (ret != chunk_size) 169cabdff1aSopenharmony_ci return AVERROR(EIO); 170cabdff1aSopenharmony_ci pkt->stream_index = roq->video_stream_index; 171cabdff1aSopenharmony_ci pkt->pts = roq->video_pts++; 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci packet_read = 1; 174cabdff1aSopenharmony_ci break; 175cabdff1aSopenharmony_ci 176cabdff1aSopenharmony_ci case RoQ_SOUND_MONO: 177cabdff1aSopenharmony_ci case RoQ_SOUND_STEREO: 178cabdff1aSopenharmony_ci if (roq->audio_stream_index == -1) { 179cabdff1aSopenharmony_ci AVStream *st = avformat_new_stream(s, NULL); 180cabdff1aSopenharmony_ci if (!st) 181cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 182cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, 1, RoQ_AUDIO_SAMPLE_RATE); 183cabdff1aSopenharmony_ci roq->audio_stream_index = st->index; 184cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 185cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_ROQ_DPCM; 186cabdff1aSopenharmony_ci st->codecpar->codec_tag = 0; /* no tag */ 187cabdff1aSopenharmony_ci if (chunk_type == RoQ_SOUND_STEREO) { 188cabdff1aSopenharmony_ci st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_STEREO; 189cabdff1aSopenharmony_ci } else { 190cabdff1aSopenharmony_ci st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; 191cabdff1aSopenharmony_ci } 192cabdff1aSopenharmony_ci roq->audio_channels = st->codecpar->ch_layout.nb_channels; 193cabdff1aSopenharmony_ci st->codecpar->sample_rate = RoQ_AUDIO_SAMPLE_RATE; 194cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample = 16; 195cabdff1aSopenharmony_ci st->codecpar->bit_rate = roq->audio_channels * st->codecpar->sample_rate * 196cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample; 197cabdff1aSopenharmony_ci st->codecpar->block_align = roq->audio_channels * st->codecpar->bits_per_coded_sample; 198cabdff1aSopenharmony_ci } 199cabdff1aSopenharmony_ci case RoQ_QUAD_VQ: 200cabdff1aSopenharmony_ci if (chunk_type == RoQ_QUAD_VQ) { 201cabdff1aSopenharmony_ci if (roq->video_stream_index < 0) 202cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 203cabdff1aSopenharmony_ci } 204cabdff1aSopenharmony_ci 205cabdff1aSopenharmony_ci /* load up the packet */ 206cabdff1aSopenharmony_ci ret = av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE); 207cabdff1aSopenharmony_ci if (ret < 0) 208cabdff1aSopenharmony_ci return ret; 209cabdff1aSopenharmony_ci /* copy over preamble */ 210cabdff1aSopenharmony_ci memcpy(pkt->data, preamble, RoQ_CHUNK_PREAMBLE_SIZE); 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_ci if (chunk_type == RoQ_QUAD_VQ) { 213cabdff1aSopenharmony_ci pkt->stream_index = roq->video_stream_index; 214cabdff1aSopenharmony_ci pkt->pts = roq->video_pts++; 215cabdff1aSopenharmony_ci } else { 216cabdff1aSopenharmony_ci pkt->stream_index = roq->audio_stream_index; 217cabdff1aSopenharmony_ci pkt->pts = roq->audio_frame_count; 218cabdff1aSopenharmony_ci roq->audio_frame_count += (chunk_size / roq->audio_channels); 219cabdff1aSopenharmony_ci } 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci pkt->pos= avio_tell(pb); 222cabdff1aSopenharmony_ci ret = avio_read(pb, pkt->data + RoQ_CHUNK_PREAMBLE_SIZE, 223cabdff1aSopenharmony_ci chunk_size); 224cabdff1aSopenharmony_ci if (ret != chunk_size) { 225cabdff1aSopenharmony_ci return AVERROR(EIO); 226cabdff1aSopenharmony_ci } 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci packet_read = 1; 229cabdff1aSopenharmony_ci break; 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci default: 232cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, " unknown RoQ chunk (%04X)\n", chunk_type); 233cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 234cabdff1aSopenharmony_ci } 235cabdff1aSopenharmony_ci } 236cabdff1aSopenharmony_ci 237cabdff1aSopenharmony_ci return ret; 238cabdff1aSopenharmony_ci} 239cabdff1aSopenharmony_ci 240cabdff1aSopenharmony_ciconst AVInputFormat ff_roq_demuxer = { 241cabdff1aSopenharmony_ci .name = "roq", 242cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("id RoQ"), 243cabdff1aSopenharmony_ci .priv_data_size = sizeof(RoqDemuxContext), 244cabdff1aSopenharmony_ci .read_probe = roq_probe, 245cabdff1aSopenharmony_ci .read_header = roq_read_header, 246cabdff1aSopenharmony_ci .read_packet = roq_read_packet, 247cabdff1aSopenharmony_ci}; 248