You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	support for Tiertex .seq files demuxing/video decoding, by Gregory Montoir %cyx A users P sourceforge P net%
Originally committed as revision 6672 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
		| @@ -61,6 +61,7 @@ version <next> | ||||
| - WavPack lossless audio decoder | ||||
| - Targa (.TGA) picture decoder | ||||
| - Delphine Software .cin demuxer/audio and video decoder | ||||
| - Tiertex .seq demuxer/video decoder | ||||
|  | ||||
| version 0.4.9-pre1: | ||||
|  | ||||
|   | ||||
| @@ -740,6 +740,8 @@ library: | ||||
| @tab Multimedia format used by Delphine Software games. | ||||
| @item MXF @tab    @tab X | ||||
| @tab Material eXchange Format SMPTE 377M, used by D-Cinema, broadcast industry. | ||||
| @item SEQ @tab    @tab X | ||||
| @tab Tiertex .seq files used in the DOS CDROM version of the game Flashback. | ||||
| @end multitable | ||||
|  | ||||
| @code{X} means that encoding (resp. decoding) is supported. | ||||
| @@ -843,6 +845,7 @@ following image formats are supported: | ||||
| @item KMVC                   @tab     @tab  X @tab Codec used in Worms games. | ||||
| @item VMware Video           @tab     @tab  X @tab Codec used in videos captured by VMware. | ||||
| @item Cin Video              @tab     @tab  X @tab Codec used in Delphine Software games. | ||||
| @item Tiertex Seq Video      @tab     @tab  X @tab Codec used in DOS CDROM FlashBack game. | ||||
| @end multitable | ||||
|  | ||||
| @code{X} means that encoding (resp. decoding) is supported. | ||||
|   | ||||
| @@ -146,6 +146,7 @@ OBJS-$(CONFIG_VCR1_ENCODER)            += vcr1.o | ||||
| OBJS-$(CONFIG_VMDAUDIO_DECODER)        += vmdav.o | ||||
| OBJS-$(CONFIG_VMDVIDEO_DECODER)        += vmdav.o | ||||
| OBJS-$(CONFIG_VMNC_DECODER)            += vmnc.o | ||||
| OBJS-$(CONFIG_TIERTEXSEQVIDEO_DECODER) += tiertexseqv.o | ||||
| OBJS-$(CONFIG_VORBIS_DECODER)          += vorbis.o vorbis_data.o | ||||
| OBJS-$(CONFIG_VORBIS_ENCODER)          += vorbis_enc.o vorbis_data.o | ||||
| OBJS-$(CONFIG_VP3_DECODER)             += vp3.o | ||||
|   | ||||
| @@ -554,6 +554,9 @@ void avcodec_register_all(void) | ||||
| #ifdef CONFIG_DSICINAUDIO_DECODER | ||||
|     register_avcodec(&dsicinaudio_decoder); | ||||
| #endif //CONFIG_DSICINAUDIO_DECODER | ||||
| #ifdef CONFIG_TIERTEXSEQVIDEO_DECODER | ||||
|     register_avcodec(&tiertexseqvideo_decoder); | ||||
| #endif //CONFIG_TIERTEXSEQVIDEO_DECODER | ||||
|  | ||||
| #if defined(CONFIG_AMR_NB) || defined(CONFIG_AMR_NB_FIXED) | ||||
| #ifdef CONFIG_AMR_NB_DECODER | ||||
|   | ||||
| @@ -37,8 +37,8 @@ extern "C" { | ||||
| #define AV_STRINGIFY(s)         AV_TOSTRING(s) | ||||
| #define AV_TOSTRING(s) #s | ||||
|  | ||||
| #define LIBAVCODEC_VERSION_INT  ((51<<16)+(18<<8)+0) | ||||
| #define LIBAVCODEC_VERSION      51.18.0 | ||||
| #define LIBAVCODEC_VERSION_INT  ((51<<16)+(19<<8)+0) | ||||
| #define LIBAVCODEC_VERSION      51.19.0 | ||||
| #define LIBAVCODEC_BUILD        LIBAVCODEC_VERSION_INT | ||||
|  | ||||
| #define LIBAVCODEC_IDENT        "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) | ||||
| @@ -146,6 +146,7 @@ enum CodecID { | ||||
|     CODEC_ID_VP6F, | ||||
|     CODEC_ID_TARGA, | ||||
|     CODEC_ID_DSICINVIDEO, | ||||
|     CODEC_ID_TIERTEXSEQVIDEO, | ||||
|  | ||||
|     /* various pcm "codecs" */ | ||||
|     CODEC_ID_PCM_S16LE= 0x10000, | ||||
| @@ -2298,6 +2299,7 @@ extern AVCodec wavpack_decoder; | ||||
| extern AVCodec targa_decoder; | ||||
| extern AVCodec dsicinvideo_decoder; | ||||
| extern AVCodec dsicinaudio_decoder; | ||||
| extern AVCodec tiertexseqvideo_decoder; | ||||
|  | ||||
| /* pcm codecs */ | ||||
| #define PCM_CODEC(id, name) \ | ||||
|   | ||||
							
								
								
									
										232
									
								
								libavcodec/tiertexseqv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								libavcodec/tiertexseqv.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,232 @@ | ||||
| /* | ||||
|  * Tiertex Limited SEQ Video Decoder | ||||
|  * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net) | ||||
|  * | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * FFmpeg is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * FFmpeg is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with FFmpeg; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @file tiertexseqv.c | ||||
|  * Tiertex Limited SEQ video decoder | ||||
|  */ | ||||
|  | ||||
| #include "avcodec.h" | ||||
| #include "common.h" | ||||
| #define ALT_BITSTREAM_READER_LE | ||||
| #include "bitstream.h" | ||||
|  | ||||
|  | ||||
| typedef struct SeqVideoContext { | ||||
|     AVCodecContext *avctx; | ||||
|     AVFrame frame; | ||||
|     unsigned int palette[256]; | ||||
|     unsigned char block[8 * 8]; | ||||
| } SeqVideoContext; | ||||
|  | ||||
|  | ||||
| static unsigned char *seq_unpack_rle_block(unsigned char *src, unsigned char *dst, int dst_size) | ||||
| { | ||||
|     int i, len, sz; | ||||
|     GetBitContext gb; | ||||
|     int code_table[64]; | ||||
|  | ||||
|     /* get the rle codes (at most 64 bytes) */ | ||||
|     init_get_bits(&gb, src, 64 * 8); | ||||
|     for (i = 0, sz = 0; i < 64 && sz < dst_size; i++) { | ||||
|         code_table[i] = get_sbits(&gb, 4); | ||||
|         sz += FFABS(code_table[i]); | ||||
|     } | ||||
|     src += (get_bits_count(&gb) + 7) / 8; | ||||
|  | ||||
|     /* do the rle unpacking */ | ||||
|     for (i = 0; i < 64 && dst_size > 0; i++) { | ||||
|         len = code_table[i]; | ||||
|         if (len < 0) { | ||||
|             len = -len; | ||||
|             memset(dst, *src++, FFMIN(len, dst_size)); | ||||
|         } else { | ||||
|             memcpy(dst, src, FFMIN(len, dst_size)); | ||||
|             src += len; | ||||
|         } | ||||
|         dst += len; | ||||
|         dst_size -= len; | ||||
|     } | ||||
|     return src; | ||||
| } | ||||
|  | ||||
| static unsigned char *seq_decode_op1(SeqVideoContext *seq, unsigned char *src, unsigned char *dst) | ||||
| { | ||||
|     unsigned char *color_table; | ||||
|     int b, i, len, bits; | ||||
|     GetBitContext gb; | ||||
|  | ||||
|     len = *src++; | ||||
|     if (len & 0x80) { | ||||
|         switch (len & 3) { | ||||
|         case 1: | ||||
|             src = seq_unpack_rle_block(src, seq->block, sizeof(seq->block)); | ||||
|             for (b = 0; b < 8; b++) { | ||||
|                 memcpy(dst, &seq->block[b * 8], 8); | ||||
|                 dst += seq->frame.linesize[0]; | ||||
|             } | ||||
|             break; | ||||
|         case 2: | ||||
|             src = seq_unpack_rle_block(src, seq->block, sizeof(seq->block)); | ||||
|             for (i = 0; i < 8; i++) { | ||||
|                 for (b = 0; b < 8; b++) | ||||
|                     dst[b * seq->frame.linesize[0]] = seq->block[i * 8 + b]; | ||||
|                 ++dst; | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|     } else { | ||||
|         color_table = src; | ||||
|         src += len; | ||||
|         bits = ff_log2_tab[len - 1] + 1; | ||||
|         init_get_bits(&gb, src, bits * 8 * 8); src += bits * 8; | ||||
|         for (b = 0; b < 8; b++) { | ||||
|             for (i = 0; i < 8; i++) | ||||
|                 dst[i] = color_table[get_bits(&gb, bits)]; | ||||
|             dst += seq->frame.linesize[0]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return src; | ||||
| } | ||||
|  | ||||
| static unsigned char *seq_decode_op2(SeqVideoContext *seq, unsigned char *src, unsigned char *dst) | ||||
| { | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < 8; i++) { | ||||
|         memcpy(dst, src, 8); | ||||
|         src += 8; | ||||
|         dst += seq->frame.linesize[0]; | ||||
|     } | ||||
|  | ||||
|     return src; | ||||
| } | ||||
|  | ||||
| static unsigned char *seq_decode_op3(SeqVideoContext *seq, unsigned char *src, unsigned char *dst) | ||||
| { | ||||
|     int pos, offset; | ||||
|  | ||||
|     do { | ||||
|         pos = *src++; | ||||
|         offset = ((pos >> 3) & 7) * seq->frame.linesize[0] + (pos & 7); | ||||
|         dst[offset] = *src++; | ||||
|     } while (!(pos & 0x80)); | ||||
|  | ||||
|     return src; | ||||
| } | ||||
|  | ||||
| static void seqvideo_decode(SeqVideoContext *seq, unsigned char *data, int data_size) | ||||
| { | ||||
|     GetBitContext gb; | ||||
|     int flags, i, j, x, y, op; | ||||
|     unsigned char c[3]; | ||||
|     unsigned char *dst; | ||||
|  | ||||
|     flags = *data++; | ||||
|  | ||||
|     if (flags & 1) { | ||||
|         for (i = 0; i < 256; i++) { | ||||
|             for (j = 0; j < 3; j++, data++) | ||||
|                 c[j] = (*data << 2) | (*data >> 4); | ||||
|             seq->palette[i] = (c[0] << 16) | (c[1] << 8) | c[2]; | ||||
|         } | ||||
|         memcpy(seq->frame.data[1], seq->palette, sizeof(seq->palette)); | ||||
|         seq->frame.palette_has_changed = 1; | ||||
|     } | ||||
|  | ||||
|     if (flags & 2) { | ||||
|         init_get_bits(&gb, data, 128 * 8); data += 128; | ||||
|         for (y = 0; y < 128; y += 8) | ||||
|             for (x = 0; x < 256; x += 8) { | ||||
|                 dst = &seq->frame.data[0][y * seq->frame.linesize[0] + x]; | ||||
|                 op = get_bits(&gb, 2); | ||||
|                 switch (op) { | ||||
|                 case 1: | ||||
|                     data = seq_decode_op1(seq, data, dst); | ||||
|                     break; | ||||
|                 case 2: | ||||
|                     data = seq_decode_op2(seq, data, dst); | ||||
|                     break; | ||||
|                 case 3: | ||||
|                     data = seq_decode_op3(seq, data, dst); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int seqvideo_decode_init(AVCodecContext *avctx) | ||||
| { | ||||
|     SeqVideoContext *seq = (SeqVideoContext *)avctx->priv_data; | ||||
|  | ||||
|     seq->avctx = avctx; | ||||
|     avctx->pix_fmt = PIX_FMT_PAL8; | ||||
|     avctx->has_b_frames = 0; | ||||
|  | ||||
|     seq->frame.data[0] = NULL; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int seqvideo_decode_frame(AVCodecContext *avctx, | ||||
|                                  void *data, int *data_size, | ||||
|                                  uint8_t *buf, int buf_size) | ||||
| { | ||||
|  | ||||
|     SeqVideoContext *seq = (SeqVideoContext *)avctx->priv_data; | ||||
|  | ||||
|     seq->frame.reference = 1; | ||||
|     seq->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; | ||||
|     if (avctx->reget_buffer(avctx, &seq->frame)) { | ||||
|         av_log(seq->avctx, AV_LOG_ERROR, "tiertexseqvideo: reget_buffer() failed\n"); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     seqvideo_decode(seq, buf, buf_size); | ||||
|  | ||||
|     *data_size = sizeof(AVFrame); | ||||
|     *(AVFrame *)data = seq->frame; | ||||
|  | ||||
|     return buf_size; | ||||
| } | ||||
|  | ||||
| static int seqvideo_decode_end(AVCodecContext *avctx) | ||||
| { | ||||
|     SeqVideoContext *seq = (SeqVideoContext *)avctx->priv_data; | ||||
|  | ||||
|     if (seq->frame.data[0]) | ||||
|         avctx->release_buffer(avctx, &seq->frame); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| AVCodec tiertexseqvideo_decoder = { | ||||
|     "tiertexseqvideo", | ||||
|     CODEC_TYPE_VIDEO, | ||||
|     CODEC_ID_TIERTEXSEQVIDEO, | ||||
|     sizeof(SeqVideoContext), | ||||
|     seqvideo_decode_init, | ||||
|     NULL, | ||||
|     seqvideo_decode_end, | ||||
|     seqvideo_decode_frame, | ||||
|     CODEC_CAP_DR1, | ||||
| }; | ||||
| @@ -130,6 +130,7 @@ OBJS-$(CONFIG_WSVQA_DEMUXER)             += westwood.o | ||||
| OBJS-$(CONFIG_WV_DEMUXER)                += wv.o | ||||
| OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER)        += yuv4mpeg.o | ||||
| OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER)      += yuv4mpeg.o | ||||
| OBJS-$(CONFIG_TIERTEXSEQ_DEMUXER)        += tiertexseq.o | ||||
|  | ||||
| # image formats | ||||
| OBJS+= pnm.o yuv.o png.o jpeg.o gifdec.o sgi.o | ||||
|   | ||||
| @@ -478,6 +478,9 @@ void av_register_all(void) | ||||
| #ifdef CONFIG_YUV4MPEGPIPE_DEMUXER | ||||
|     av_register_input_format(&yuv4mpegpipe_demuxer); | ||||
| #endif | ||||
| #ifdef CONFIG_TIERTEXSEQ_DEMUXER | ||||
|     av_register_input_format(&tiertexseq_demuxer); | ||||
| #endif | ||||
|  | ||||
|     /* image formats */ | ||||
| #if 0 | ||||
|   | ||||
| @@ -162,6 +162,7 @@ extern AVInputFormat wsvqa_demuxer; | ||||
| extern AVInputFormat wv_demuxer; | ||||
| extern AVOutputFormat yuv4mpegpipe_muxer; | ||||
| extern AVInputFormat yuv4mpegpipe_demuxer; | ||||
| extern AVInputFormat tiertexseq_demuxer; | ||||
|  | ||||
| /* raw.c */ | ||||
| int pcm_read_seek(AVFormatContext *s, | ||||
|   | ||||
| @@ -25,8 +25,8 @@ | ||||
| extern "C" { | ||||
| #endif | ||||
|  | ||||
| #define LIBAVFORMAT_VERSION_INT ((50<<16)+(5<<8)+0) | ||||
| #define LIBAVFORMAT_VERSION     50.5.0 | ||||
| #define LIBAVFORMAT_VERSION_INT ((50<<16)+(6<<8)+0) | ||||
| #define LIBAVFORMAT_VERSION     50.6.0 | ||||
| #define LIBAVFORMAT_BUILD       LIBAVFORMAT_VERSION_INT | ||||
|  | ||||
| #define LIBAVFORMAT_IDENT       "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) | ||||
|   | ||||
							
								
								
									
										305
									
								
								libavformat/tiertexseq.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								libavformat/tiertexseq.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,305 @@ | ||||
| /* | ||||
|  * Tiertex Limited SEQ File Demuxer | ||||
|  * Copyright (c) 2006 Gregory Montoir (cyx@users.sourceforge.net) | ||||
|  * | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * FFmpeg is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * FFmpeg is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with FFmpeg; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * @file tiertexseq.c | ||||
|  * Tiertex Limited SEQ file demuxer | ||||
|  */ | ||||
|  | ||||
| #include "avformat.h" | ||||
|  | ||||
| #define SEQ_FRAME_SIZE         6144 | ||||
| #define SEQ_FRAME_W            256 | ||||
| #define SEQ_FRAME_H            128 | ||||
| #define SEQ_NUM_FRAME_BUFFERS  30 | ||||
| #define SEQ_AUDIO_BUFFER_SIZE  882 | ||||
| #define SEQ_SAMPLE_RATE        22050 | ||||
| #define SEQ_FRAME_RATE         25 | ||||
|  | ||||
|  | ||||
| typedef struct TiertexSeqFrameBuffer { | ||||
|     int fill_size; | ||||
|     int data_size; | ||||
|     unsigned char *data; | ||||
| } TiertexSeqFrameBuffer; | ||||
|  | ||||
| typedef struct SeqDemuxContext { | ||||
|     int audio_stream_index; | ||||
|     int video_stream_index; | ||||
|     int current_frame_pts; | ||||
|     int current_frame_offs; | ||||
|     TiertexSeqFrameBuffer frame_buffers[SEQ_NUM_FRAME_BUFFERS]; | ||||
|     int frame_buffers_count; | ||||
|     unsigned int current_audio_data_size; | ||||
|     unsigned int current_audio_data_offs; | ||||
|     unsigned int current_pal_data_size; | ||||
|     unsigned int current_pal_data_offs; | ||||
|     unsigned int current_video_data_size; | ||||
|     unsigned char *current_video_data_ptr; | ||||
|     int audio_buffer_full; | ||||
| } SeqDemuxContext; | ||||
|  | ||||
|  | ||||
| static int seq_probe(AVProbeData *p) | ||||
| { | ||||
|     int i; | ||||
|  | ||||
|     if (p->buf_size < 256) | ||||
|         return 0; | ||||
|  | ||||
|     /* there's no real header in a .seq file, the only thing they have in common */ | ||||
|     /* is the first 256 bytes of the file which are always filled with 0 */ | ||||
|     for (i = 0; i < 256; i++) | ||||
|         if (p->buf[0] != 0) | ||||
|             return 0; | ||||
|  | ||||
|     /* only one fourth of the score since the previous check is too naive */ | ||||
|     return AVPROBE_SCORE_MAX / 4; | ||||
| } | ||||
|  | ||||
| static int seq_init_frame_buffers(SeqDemuxContext *seq, ByteIOContext *pb) | ||||
| { | ||||
|     int i, sz; | ||||
|     TiertexSeqFrameBuffer *seq_buffer; | ||||
|  | ||||
|     url_fseek(pb, 256, SEEK_SET); | ||||
|  | ||||
|     for (i = 0; i < SEQ_NUM_FRAME_BUFFERS; i++) { | ||||
|         sz = get_le16(pb); | ||||
|         if (sz == 0) | ||||
|             break; | ||||
|         else { | ||||
|             seq_buffer = &seq->frame_buffers[i]; | ||||
|             seq_buffer->fill_size = 0; | ||||
|             seq_buffer->data_size = sz; | ||||
|             seq_buffer->data = av_malloc(sz); | ||||
|             if (!seq_buffer->data) | ||||
|                 return AVERROR_NOMEM; | ||||
|         } | ||||
|     } | ||||
|     seq->frame_buffers_count = i; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int seq_fill_buffer(SeqDemuxContext *seq, ByteIOContext *pb, int buffer_num, unsigned int data_offs, int data_size) | ||||
| { | ||||
|     TiertexSeqFrameBuffer *seq_buffer; | ||||
|  | ||||
|     if (buffer_num >= SEQ_NUM_FRAME_BUFFERS) | ||||
|         return AVERROR_INVALIDDATA; | ||||
|  | ||||
|     seq_buffer = &seq->frame_buffers[buffer_num]; | ||||
|     if (seq_buffer->fill_size + data_size > seq_buffer->data_size) | ||||
|         return AVERROR_INVALIDDATA; | ||||
|  | ||||
|     url_fseek(pb, seq->current_frame_offs + data_offs, SEEK_SET); | ||||
|     if (get_buffer(pb, seq_buffer->data + seq_buffer->fill_size, data_size) != data_size) | ||||
|         return AVERROR_IO; | ||||
|  | ||||
|     seq_buffer->fill_size += data_size; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int seq_parse_frame_data(SeqDemuxContext *seq, ByteIOContext *pb) | ||||
| { | ||||
|     unsigned int offset_table[4], buffer_num[4]; | ||||
|     TiertexSeqFrameBuffer *seq_buffer; | ||||
|     int i, e; | ||||
|  | ||||
|     seq->current_frame_offs += SEQ_FRAME_SIZE; | ||||
|     url_fseek(pb, seq->current_frame_offs, SEEK_SET); | ||||
|  | ||||
|     /* sound data */ | ||||
|     seq->current_audio_data_offs = get_le16(pb); | ||||
|     if (seq->current_audio_data_offs != 0) { | ||||
|         seq->current_audio_data_size = SEQ_AUDIO_BUFFER_SIZE * 2; | ||||
|     } else { | ||||
|         seq->current_audio_data_size = 0; | ||||
|     } | ||||
|  | ||||
|     /* palette data */ | ||||
|     seq->current_pal_data_offs = get_le16(pb); | ||||
|     if (seq->current_pal_data_offs != 0) { | ||||
|         seq->current_pal_data_size = 768; | ||||
|     } else { | ||||
|         seq->current_pal_data_size = 0; | ||||
|     } | ||||
|  | ||||
|     /* video data */ | ||||
|     for (i = 0; i < 4; i++) | ||||
|         buffer_num[i] = get_byte(pb); | ||||
|  | ||||
|     for (i = 0; i < 4; i++) | ||||
|         offset_table[i] = get_le16(pb); | ||||
|  | ||||
|     for (i = 0; i < 3; i++) { | ||||
|         if (offset_table[i] != 0) { | ||||
|             for (e = i + 1; e < 4 && offset_table[e] == 0; e++); | ||||
|             seq_fill_buffer(seq, pb, buffer_num[1 + i], | ||||
|               offset_table[i], | ||||
|               offset_table[e] - offset_table[i]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (buffer_num[0] != 255) { | ||||
|         seq_buffer = &seq->frame_buffers[buffer_num[0]]; | ||||
|         seq->current_video_data_size = seq_buffer->fill_size; | ||||
|         seq->current_video_data_ptr  = seq_buffer->data; | ||||
|         seq_buffer->fill_size = 0; | ||||
|     } else { | ||||
|         seq->current_video_data_size = 0; | ||||
|         seq->current_video_data_ptr  = 0; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int seq_read_header(AVFormatContext *s, AVFormatParameters *ap) | ||||
| { | ||||
|     int i, rc; | ||||
|     SeqDemuxContext *seq = (SeqDemuxContext *)s->priv_data; | ||||
|     ByteIOContext *pb = &s->pb; | ||||
|     AVStream *st; | ||||
|  | ||||
|     /* init internal buffers */ | ||||
|     rc = seq_init_frame_buffers(seq, pb); | ||||
|     if (rc) | ||||
|         return rc; | ||||
|  | ||||
|     seq->current_frame_offs = 0; | ||||
|  | ||||
|     /* preload (no audio data, just buffer operations related data) */ | ||||
|     for (i = 1; i <= 100; i++) { | ||||
|         rc = seq_parse_frame_data(seq, pb); | ||||
|         if (rc) | ||||
|             return rc; | ||||
|     } | ||||
|  | ||||
|     seq->current_frame_pts = 0; | ||||
|  | ||||
|     seq->audio_buffer_full = 0; | ||||
|  | ||||
|     /* initialize the video decoder stream */ | ||||
|     st = av_new_stream(s, 0); | ||||
|     if (!st) | ||||
|         return AVERROR_NOMEM; | ||||
|  | ||||
|     av_set_pts_info(st, 32, 1, SEQ_FRAME_RATE); | ||||
|     seq->video_stream_index = st->index; | ||||
|     st->codec->codec_type = CODEC_TYPE_VIDEO; | ||||
|     st->codec->codec_id = CODEC_ID_TIERTEXSEQVIDEO; | ||||
|     st->codec->codec_tag = 0;  /* no fourcc */ | ||||
|     st->codec->width = SEQ_FRAME_W; | ||||
|     st->codec->height = SEQ_FRAME_H; | ||||
|  | ||||
|     /* initialize the audio decoder stream */ | ||||
|     st = av_new_stream(s, 0); | ||||
|     if (!st) | ||||
|         return AVERROR_NOMEM; | ||||
|  | ||||
|     av_set_pts_info(st, 32, 1, SEQ_SAMPLE_RATE); | ||||
|     seq->audio_stream_index = st->index; | ||||
|     st->codec->codec_type = CODEC_TYPE_AUDIO; | ||||
|     st->codec->codec_id = CODEC_ID_PCM_S16BE; | ||||
|     st->codec->codec_tag = 0;  /* no tag */ | ||||
|     st->codec->channels = 1; | ||||
|     st->codec->sample_rate = SEQ_SAMPLE_RATE; | ||||
|     st->codec->bits_per_sample = 16; | ||||
|     st->codec->bit_rate = st->codec->sample_rate * st->codec->bits_per_sample * st->codec->channels; | ||||
|     st->codec->block_align = st->codec->channels * st->codec->bits_per_sample; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int seq_read_packet(AVFormatContext *s, AVPacket *pkt) | ||||
| { | ||||
|     int rc; | ||||
|     SeqDemuxContext *seq = (SeqDemuxContext *)s->priv_data; | ||||
|     ByteIOContext *pb = &s->pb; | ||||
|  | ||||
|     if (!seq->audio_buffer_full) { | ||||
|         rc = seq_parse_frame_data(seq, pb); | ||||
|         if (rc) | ||||
|             return rc; | ||||
|  | ||||
|         /* video packet */ | ||||
|         if (seq->current_pal_data_size + seq->current_video_data_size != 0) { | ||||
|             if (av_new_packet(pkt, 1 + seq->current_pal_data_size + seq->current_video_data_size)) | ||||
|                 return AVERROR_NOMEM; | ||||
|  | ||||
|             pkt->data[0] = 0; | ||||
|             if (seq->current_pal_data_size != 0) { | ||||
|                 pkt->data[0] |= 1; | ||||
|                 url_fseek(pb, seq->current_frame_offs + seq->current_pal_data_offs, SEEK_SET); | ||||
|                 if (get_buffer(pb, &pkt->data[1], seq->current_pal_data_size) != seq->current_pal_data_size) | ||||
|                     return AVERROR_IO; | ||||
|             } | ||||
|             if (seq->current_video_data_size != 0) { | ||||
|                 pkt->data[0] |= 2; | ||||
|                 memcpy(&pkt->data[1 + seq->current_pal_data_size], | ||||
|                   seq->current_video_data_ptr, | ||||
|                   seq->current_video_data_size); | ||||
|             } | ||||
|             pkt->stream_index = seq->video_stream_index; | ||||
|             pkt->pts = seq->current_frame_pts; | ||||
|  | ||||
|             /* sound buffer will be processed on next read_packet() call */ | ||||
|             seq->audio_buffer_full = 1; | ||||
|             return 0; | ||||
|        } | ||||
|     } | ||||
|  | ||||
|     /* audio packet */ | ||||
|     if (seq->current_audio_data_offs == 0) /* end of data reached */ | ||||
|         return AVERROR_IO; | ||||
|  | ||||
|     url_fseek(pb, seq->current_frame_offs + seq->current_audio_data_offs, SEEK_SET); | ||||
|     rc = av_get_packet(pb, pkt, seq->current_audio_data_size); | ||||
|     if (rc < 0) | ||||
|         return rc; | ||||
|  | ||||
|     pkt->stream_index = seq->audio_stream_index; | ||||
|     pkt->pts = seq->current_frame_pts++; | ||||
|  | ||||
|     seq->audio_buffer_full = 0; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int seq_read_close(AVFormatContext *s) | ||||
| { | ||||
|     int i; | ||||
|     SeqDemuxContext *seq = (SeqDemuxContext *)s->priv_data; | ||||
|  | ||||
|     for (i = 0; i < SEQ_NUM_FRAME_BUFFERS; i++) | ||||
|         av_free(seq->frame_buffers[i].data); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| AVInputFormat tiertexseq_demuxer = { | ||||
|     "tiertexseq", | ||||
|     "Tiertex Limited SEQ format", | ||||
|     sizeof(SeqDemuxContext), | ||||
|     seq_probe, | ||||
|     seq_read_header, | ||||
|     seq_read_packet, | ||||
|     seq_read_close, | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user