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