1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Tiertex Limited SEQ File Demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net) 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 * Tiertex Limited SEQ file demuxer 25cabdff1aSopenharmony_ci */ 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h" 28cabdff1aSopenharmony_ci#include "avformat.h" 29cabdff1aSopenharmony_ci#include "internal.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_ci#define SEQ_FRAME_SIZE 6144 32cabdff1aSopenharmony_ci#define SEQ_FRAME_W 256 33cabdff1aSopenharmony_ci#define SEQ_FRAME_H 128 34cabdff1aSopenharmony_ci#define SEQ_NUM_FRAME_BUFFERS 30 35cabdff1aSopenharmony_ci#define SEQ_AUDIO_BUFFER_SIZE 882 36cabdff1aSopenharmony_ci#define SEQ_SAMPLE_RATE 22050 37cabdff1aSopenharmony_ci#define SEQ_FRAME_RATE 25 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_citypedef struct TiertexSeqFrameBuffer { 41cabdff1aSopenharmony_ci int fill_size; 42cabdff1aSopenharmony_ci int data_size; 43cabdff1aSopenharmony_ci unsigned char *data; 44cabdff1aSopenharmony_ci} TiertexSeqFrameBuffer; 45cabdff1aSopenharmony_ci 46cabdff1aSopenharmony_citypedef struct SeqDemuxContext { 47cabdff1aSopenharmony_ci int audio_stream_index; 48cabdff1aSopenharmony_ci int video_stream_index; 49cabdff1aSopenharmony_ci int current_frame_pts; 50cabdff1aSopenharmony_ci int current_frame_offs; 51cabdff1aSopenharmony_ci TiertexSeqFrameBuffer frame_buffers[SEQ_NUM_FRAME_BUFFERS]; 52cabdff1aSopenharmony_ci int frame_buffers_count; 53cabdff1aSopenharmony_ci unsigned int current_audio_data_size; 54cabdff1aSopenharmony_ci unsigned int current_audio_data_offs; 55cabdff1aSopenharmony_ci unsigned int current_pal_data_size; 56cabdff1aSopenharmony_ci unsigned int current_pal_data_offs; 57cabdff1aSopenharmony_ci unsigned int current_video_data_size; 58cabdff1aSopenharmony_ci unsigned char *current_video_data_ptr; 59cabdff1aSopenharmony_ci int audio_buffer_full; 60cabdff1aSopenharmony_ci} SeqDemuxContext; 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_cistatic int seq_probe(const AVProbeData *p) 64cabdff1aSopenharmony_ci{ 65cabdff1aSopenharmony_ci int i; 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci if (p->buf_size < 258) 68cabdff1aSopenharmony_ci return 0; 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_ci /* there's no real header in a .seq file, the only thing they have in common */ 71cabdff1aSopenharmony_ci /* is the first 256 bytes of the file which are always filled with 0 */ 72cabdff1aSopenharmony_ci for (i = 0; i < 256; i++) 73cabdff1aSopenharmony_ci if (p->buf[i]) 74cabdff1aSopenharmony_ci return 0; 75cabdff1aSopenharmony_ci 76cabdff1aSopenharmony_ci if(p->buf[256]==0 && p->buf[257]==0) 77cabdff1aSopenharmony_ci return 0; 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_ci /* only one fourth of the score since the previous check is too naive */ 80cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX / 4; 81cabdff1aSopenharmony_ci} 82cabdff1aSopenharmony_ci 83cabdff1aSopenharmony_cistatic int seq_init_frame_buffers(SeqDemuxContext *seq, AVIOContext *pb) 84cabdff1aSopenharmony_ci{ 85cabdff1aSopenharmony_ci int i, sz; 86cabdff1aSopenharmony_ci TiertexSeqFrameBuffer *seq_buffer; 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci avio_seek(pb, 256, SEEK_SET); 89cabdff1aSopenharmony_ci 90cabdff1aSopenharmony_ci for (i = 0; i < SEQ_NUM_FRAME_BUFFERS; i++) { 91cabdff1aSopenharmony_ci sz = avio_rl16(pb); 92cabdff1aSopenharmony_ci if (sz == 0) 93cabdff1aSopenharmony_ci break; 94cabdff1aSopenharmony_ci else { 95cabdff1aSopenharmony_ci seq_buffer = &seq->frame_buffers[i]; 96cabdff1aSopenharmony_ci seq_buffer->fill_size = 0; 97cabdff1aSopenharmony_ci seq_buffer->data_size = sz; 98cabdff1aSopenharmony_ci seq_buffer->data = av_malloc(sz); 99cabdff1aSopenharmony_ci if (!seq_buffer->data) 100cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 101cabdff1aSopenharmony_ci } 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci seq->frame_buffers_count = i; 104cabdff1aSopenharmony_ci return 0; 105cabdff1aSopenharmony_ci} 106cabdff1aSopenharmony_ci 107cabdff1aSopenharmony_cistatic int seq_fill_buffer(SeqDemuxContext *seq, AVIOContext *pb, int buffer_num, unsigned int data_offs, int data_size) 108cabdff1aSopenharmony_ci{ 109cabdff1aSopenharmony_ci TiertexSeqFrameBuffer *seq_buffer; 110cabdff1aSopenharmony_ci 111cabdff1aSopenharmony_ci if (buffer_num >= SEQ_NUM_FRAME_BUFFERS) 112cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 113cabdff1aSopenharmony_ci 114cabdff1aSopenharmony_ci seq_buffer = &seq->frame_buffers[buffer_num]; 115cabdff1aSopenharmony_ci if (seq_buffer->fill_size + data_size > seq_buffer->data_size || data_size <= 0) 116cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 117cabdff1aSopenharmony_ci 118cabdff1aSopenharmony_ci avio_seek(pb, seq->current_frame_offs + data_offs, SEEK_SET); 119cabdff1aSopenharmony_ci if (avio_read(pb, seq_buffer->data + seq_buffer->fill_size, data_size) != data_size) 120cabdff1aSopenharmony_ci return AVERROR(EIO); 121cabdff1aSopenharmony_ci 122cabdff1aSopenharmony_ci seq_buffer->fill_size += data_size; 123cabdff1aSopenharmony_ci return 0; 124cabdff1aSopenharmony_ci} 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_cistatic int seq_parse_frame_data(SeqDemuxContext *seq, AVIOContext *pb) 127cabdff1aSopenharmony_ci{ 128cabdff1aSopenharmony_ci unsigned int offset_table[4], buffer_num[4]; 129cabdff1aSopenharmony_ci TiertexSeqFrameBuffer *seq_buffer; 130cabdff1aSopenharmony_ci int i, e, err; 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci seq->current_frame_offs += SEQ_FRAME_SIZE; 133cabdff1aSopenharmony_ci avio_seek(pb, seq->current_frame_offs, SEEK_SET); 134cabdff1aSopenharmony_ci 135cabdff1aSopenharmony_ci /* sound data */ 136cabdff1aSopenharmony_ci seq->current_audio_data_offs = avio_rl16(pb); 137cabdff1aSopenharmony_ci if (seq->current_audio_data_offs) { 138cabdff1aSopenharmony_ci seq->current_audio_data_size = SEQ_AUDIO_BUFFER_SIZE * 2; 139cabdff1aSopenharmony_ci } else { 140cabdff1aSopenharmony_ci seq->current_audio_data_size = 0; 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci /* palette data */ 144cabdff1aSopenharmony_ci seq->current_pal_data_offs = avio_rl16(pb); 145cabdff1aSopenharmony_ci if (seq->current_pal_data_offs) { 146cabdff1aSopenharmony_ci seq->current_pal_data_size = 768; 147cabdff1aSopenharmony_ci } else { 148cabdff1aSopenharmony_ci seq->current_pal_data_size = 0; 149cabdff1aSopenharmony_ci } 150cabdff1aSopenharmony_ci 151cabdff1aSopenharmony_ci /* video data */ 152cabdff1aSopenharmony_ci for (i = 0; i < 4; i++) 153cabdff1aSopenharmony_ci buffer_num[i] = avio_r8(pb); 154cabdff1aSopenharmony_ci 155cabdff1aSopenharmony_ci for (i = 0; i < 4; i++) 156cabdff1aSopenharmony_ci offset_table[i] = avio_rl16(pb); 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci for (i = 0; i < 3; i++) { 159cabdff1aSopenharmony_ci if (offset_table[i]) { 160cabdff1aSopenharmony_ci for (e = i + 1; e < 3 && offset_table[e] == 0; e++); 161cabdff1aSopenharmony_ci err = seq_fill_buffer(seq, pb, buffer_num[1 + i], 162cabdff1aSopenharmony_ci offset_table[i], 163cabdff1aSopenharmony_ci offset_table[e] - offset_table[i]); 164cabdff1aSopenharmony_ci if (err) 165cabdff1aSopenharmony_ci return err; 166cabdff1aSopenharmony_ci } 167cabdff1aSopenharmony_ci } 168cabdff1aSopenharmony_ci 169cabdff1aSopenharmony_ci if (buffer_num[0] != 255) { 170cabdff1aSopenharmony_ci if (buffer_num[0] >= SEQ_NUM_FRAME_BUFFERS) 171cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci seq_buffer = &seq->frame_buffers[buffer_num[0]]; 174cabdff1aSopenharmony_ci seq->current_video_data_size = seq_buffer->fill_size; 175cabdff1aSopenharmony_ci seq->current_video_data_ptr = seq_buffer->data; 176cabdff1aSopenharmony_ci seq_buffer->fill_size = 0; 177cabdff1aSopenharmony_ci } else { 178cabdff1aSopenharmony_ci seq->current_video_data_size = 0; 179cabdff1aSopenharmony_ci seq->current_video_data_ptr = 0; 180cabdff1aSopenharmony_ci } 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci return 0; 183cabdff1aSopenharmony_ci} 184cabdff1aSopenharmony_ci 185cabdff1aSopenharmony_cistatic int seq_read_close(AVFormatContext *s) 186cabdff1aSopenharmony_ci{ 187cabdff1aSopenharmony_ci int i; 188cabdff1aSopenharmony_ci SeqDemuxContext *seq = s->priv_data; 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci for (i = 0; i < SEQ_NUM_FRAME_BUFFERS; i++) 191cabdff1aSopenharmony_ci av_freep(&seq->frame_buffers[i].data); 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_ci return 0; 194cabdff1aSopenharmony_ci} 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_cistatic int seq_read_header(AVFormatContext *s) 197cabdff1aSopenharmony_ci{ 198cabdff1aSopenharmony_ci int i, rc; 199cabdff1aSopenharmony_ci SeqDemuxContext *seq = s->priv_data; 200cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 201cabdff1aSopenharmony_ci AVStream *st; 202cabdff1aSopenharmony_ci 203cabdff1aSopenharmony_ci /* init internal buffers */ 204cabdff1aSopenharmony_ci rc = seq_init_frame_buffers(seq, pb); 205cabdff1aSopenharmony_ci if (rc < 0) 206cabdff1aSopenharmony_ci return rc; 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci seq->current_frame_offs = 0; 209cabdff1aSopenharmony_ci 210cabdff1aSopenharmony_ci /* preload (no audio data, just buffer operations related data) */ 211cabdff1aSopenharmony_ci for (i = 1; i <= 100; i++) { 212cabdff1aSopenharmony_ci rc = seq_parse_frame_data(seq, pb); 213cabdff1aSopenharmony_ci if (rc < 0) 214cabdff1aSopenharmony_ci return rc; 215cabdff1aSopenharmony_ci } 216cabdff1aSopenharmony_ci 217cabdff1aSopenharmony_ci seq->current_frame_pts = 0; 218cabdff1aSopenharmony_ci 219cabdff1aSopenharmony_ci seq->audio_buffer_full = 0; 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci /* initialize the video decoder stream */ 222cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 223cabdff1aSopenharmony_ci if (!st) 224cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, 1, SEQ_FRAME_RATE); 227cabdff1aSopenharmony_ci seq->video_stream_index = st->index; 228cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 229cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_TIERTEXSEQVIDEO; 230cabdff1aSopenharmony_ci st->codecpar->codec_tag = 0; /* no fourcc */ 231cabdff1aSopenharmony_ci st->codecpar->width = SEQ_FRAME_W; 232cabdff1aSopenharmony_ci st->codecpar->height = SEQ_FRAME_H; 233cabdff1aSopenharmony_ci 234cabdff1aSopenharmony_ci /* initialize the audio decoder stream */ 235cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 236cabdff1aSopenharmony_ci if (!st) 237cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci st->start_time = 0; 240cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, 1, SEQ_SAMPLE_RATE); 241cabdff1aSopenharmony_ci seq->audio_stream_index = st->index; 242cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 243cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE; 244cabdff1aSopenharmony_ci st->codecpar->codec_tag = 0; /* no tag */ 245cabdff1aSopenharmony_ci st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; 246cabdff1aSopenharmony_ci st->codecpar->sample_rate = SEQ_SAMPLE_RATE; 247cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample = 16; 248cabdff1aSopenharmony_ci st->codecpar->bit_rate = st->codecpar->sample_rate * st->codecpar->bits_per_coded_sample * st->codecpar->ch_layout.nb_channels; 249cabdff1aSopenharmony_ci st->codecpar->block_align = st->codecpar->ch_layout.nb_channels * st->codecpar->bits_per_coded_sample / 8; 250cabdff1aSopenharmony_ci 251cabdff1aSopenharmony_ci return 0; 252cabdff1aSopenharmony_ci} 253cabdff1aSopenharmony_ci 254cabdff1aSopenharmony_cistatic int seq_read_packet(AVFormatContext *s, AVPacket *pkt) 255cabdff1aSopenharmony_ci{ 256cabdff1aSopenharmony_ci int rc; 257cabdff1aSopenharmony_ci SeqDemuxContext *seq = s->priv_data; 258cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_ci if (!seq->audio_buffer_full) { 261cabdff1aSopenharmony_ci rc = seq_parse_frame_data(seq, pb); 262cabdff1aSopenharmony_ci if (rc) 263cabdff1aSopenharmony_ci return rc; 264cabdff1aSopenharmony_ci 265cabdff1aSopenharmony_ci /* video packet */ 266cabdff1aSopenharmony_ci if (seq->current_pal_data_size + seq->current_video_data_size != 0) { 267cabdff1aSopenharmony_ci rc = av_new_packet(pkt, 1 + seq->current_pal_data_size 268cabdff1aSopenharmony_ci + seq->current_video_data_size); 269cabdff1aSopenharmony_ci if (rc < 0) 270cabdff1aSopenharmony_ci return rc; 271cabdff1aSopenharmony_ci 272cabdff1aSopenharmony_ci pkt->data[0] = 0; 273cabdff1aSopenharmony_ci if (seq->current_pal_data_size) { 274cabdff1aSopenharmony_ci pkt->data[0] |= 1; 275cabdff1aSopenharmony_ci avio_seek(pb, seq->current_frame_offs + seq->current_pal_data_offs, SEEK_SET); 276cabdff1aSopenharmony_ci if (avio_read(pb, &pkt->data[1], seq->current_pal_data_size) != seq->current_pal_data_size) 277cabdff1aSopenharmony_ci return AVERROR(EIO); 278cabdff1aSopenharmony_ci } 279cabdff1aSopenharmony_ci if (seq->current_video_data_size) { 280cabdff1aSopenharmony_ci pkt->data[0] |= 2; 281cabdff1aSopenharmony_ci memcpy(&pkt->data[1 + seq->current_pal_data_size], 282cabdff1aSopenharmony_ci seq->current_video_data_ptr, 283cabdff1aSopenharmony_ci seq->current_video_data_size); 284cabdff1aSopenharmony_ci } 285cabdff1aSopenharmony_ci pkt->stream_index = seq->video_stream_index; 286cabdff1aSopenharmony_ci pkt->pts = seq->current_frame_pts; 287cabdff1aSopenharmony_ci 288cabdff1aSopenharmony_ci /* sound buffer will be processed on next read_packet() call */ 289cabdff1aSopenharmony_ci seq->audio_buffer_full = 1; 290cabdff1aSopenharmony_ci return 0; 291cabdff1aSopenharmony_ci } 292cabdff1aSopenharmony_ci } 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci /* audio packet */ 295cabdff1aSopenharmony_ci if (seq->current_audio_data_offs == 0) /* end of data reached */ 296cabdff1aSopenharmony_ci return AVERROR(EIO); 297cabdff1aSopenharmony_ci 298cabdff1aSopenharmony_ci avio_seek(pb, seq->current_frame_offs + seq->current_audio_data_offs, SEEK_SET); 299cabdff1aSopenharmony_ci rc = av_get_packet(pb, pkt, seq->current_audio_data_size); 300cabdff1aSopenharmony_ci if (rc < 0) 301cabdff1aSopenharmony_ci return rc; 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci pkt->stream_index = seq->audio_stream_index; 304cabdff1aSopenharmony_ci seq->current_frame_pts++; 305cabdff1aSopenharmony_ci 306cabdff1aSopenharmony_ci seq->audio_buffer_full = 0; 307cabdff1aSopenharmony_ci return 0; 308cabdff1aSopenharmony_ci} 309cabdff1aSopenharmony_ci 310cabdff1aSopenharmony_ciconst AVInputFormat ff_tiertexseq_demuxer = { 311cabdff1aSopenharmony_ci .name = "tiertexseq", 312cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Tiertex Limited SEQ"), 313cabdff1aSopenharmony_ci .priv_data_size = sizeof(SeqDemuxContext), 314cabdff1aSopenharmony_ci .flags_internal = FF_FMT_INIT_CLEANUP, 315cabdff1aSopenharmony_ci .read_probe = seq_probe, 316cabdff1aSopenharmony_ci .read_header = seq_read_header, 317cabdff1aSopenharmony_ci .read_packet = seq_read_packet, 318cabdff1aSopenharmony_ci .read_close = seq_read_close, 319cabdff1aSopenharmony_ci}; 320