| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2010-04-20 14:45:34 +00:00
										 |  |  |  * @file | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |  * Tiertex Limited SEQ video decoder | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "avcodec.h"
 | 
					
						
							|  |  |  | #define ALT_BITSTREAM_READER_LE
 | 
					
						
							| 
									
										
										
										
											2009-04-13 16:20:26 +00:00
										 |  |  | #include "get_bits.h"
 | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct SeqVideoContext { | 
					
						
							|  |  |  |     AVCodecContext *avctx; | 
					
						
							|  |  |  |     AVFrame frame; | 
					
						
							|  |  |  | } SeqVideoContext; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  | static const unsigned char *seq_unpack_rle_block(const unsigned char *src, | 
					
						
							|  |  |  |                                                  const unsigned char *src_end, | 
					
						
							|  |  |  |                                                  unsigned char *dst, int dst_size) | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int i, len, sz; | 
					
						
							|  |  |  |     GetBitContext gb; | 
					
						
							|  |  |  |     int code_table[64]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |     /* get the rle codes */ | 
					
						
							|  |  |  |     init_get_bits(&gb, src, (src_end - src) * 8); | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |     for (i = 0, sz = 0; i < 64 && sz < dst_size; i++) { | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |         if (get_bits_left(&gb) < 4) | 
					
						
							|  |  |  |             return NULL; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |         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; | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |             if (src_end - src < 1) | 
					
						
							|  |  |  |                 return NULL; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |             memset(dst, *src++, FFMIN(len, dst_size)); | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |             if (src_end - src < len) | 
					
						
							|  |  |  |                 return NULL; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |             memcpy(dst, src, FFMIN(len, dst_size)); | 
					
						
							|  |  |  |             src += len; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         dst += len; | 
					
						
							|  |  |  |         dst_size -= len; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return src; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  | static const unsigned char *seq_decode_op1(SeqVideoContext *seq, | 
					
						
							|  |  |  |                                            const unsigned char *src, | 
					
						
							|  |  |  |                                            const unsigned char *src_end, | 
					
						
							|  |  |  |                                            unsigned char *dst) | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-02-01 15:56:51 +00:00
										 |  |  |     const unsigned char *color_table; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |     int b, i, len, bits; | 
					
						
							|  |  |  |     GetBitContext gb; | 
					
						
							| 
									
										
										
										
											2008-07-06 10:01:54 +00:00
										 |  |  |     unsigned char block[8 * 8]; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |     if (src_end - src < 1) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |     len = *src++; | 
					
						
							|  |  |  |     if (len & 0x80) { | 
					
						
							|  |  |  |         switch (len & 3) { | 
					
						
							|  |  |  |         case 1: | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |             src = seq_unpack_rle_block(src, src_end, block, sizeof(block)); | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |             for (b = 0; b < 8; b++) { | 
					
						
							| 
									
										
										
										
											2008-07-06 10:01:54 +00:00
										 |  |  |                 memcpy(dst, &block[b * 8], 8); | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |                 dst += seq->frame.linesize[0]; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 2: | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |             src = seq_unpack_rle_block(src, src_end, block, sizeof(block)); | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |             for (i = 0; i < 8; i++) { | 
					
						
							|  |  |  |                 for (b = 0; b < 8; b++) | 
					
						
							| 
									
										
										
										
											2008-07-06 10:01:54 +00:00
										 |  |  |                     dst[b * seq->frame.linesize[0]] = block[i * 8 + b]; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |                 ++dst; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |         if (len <= 0) | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         bits = ff_log2_tab[len - 1] + 1; | 
					
						
							|  |  |  |         if (src_end - src < len + 8 * bits) | 
					
						
							|  |  |  |             return NULL; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |         color_table = src; | 
					
						
							|  |  |  |         src += len; | 
					
						
							|  |  |  |         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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  | static const unsigned char *seq_decode_op2(SeqVideoContext *seq, | 
					
						
							|  |  |  |                                            const unsigned char *src, | 
					
						
							|  |  |  |                                            const unsigned char *src_end, | 
					
						
							|  |  |  |                                            unsigned char *dst) | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |     if (src_end - src < 8 * 8) | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |     for (i = 0; i < 8; i++) { | 
					
						
							|  |  |  |         memcpy(dst, src, 8); | 
					
						
							|  |  |  |         src += 8; | 
					
						
							|  |  |  |         dst += seq->frame.linesize[0]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return src; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  | static const unsigned char *seq_decode_op3(SeqVideoContext *seq, | 
					
						
							|  |  |  |                                            const unsigned char *src, | 
					
						
							|  |  |  |                                            const unsigned char *src_end, | 
					
						
							|  |  |  |                                            unsigned char *dst) | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int pos, offset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     do { | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |         if (src_end - src < 2) | 
					
						
							|  |  |  |             return NULL; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |         pos = *src++; | 
					
						
							|  |  |  |         offset = ((pos >> 3) & 7) * seq->frame.linesize[0] + (pos & 7); | 
					
						
							|  |  |  |         dst[offset] = *src++; | 
					
						
							|  |  |  |     } while (!(pos & 0x80)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return src; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  | static int seqvideo_decode(SeqVideoContext *seq, const unsigned char *data, int data_size) | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |     const unsigned char *data_end = data + data_size; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |     GetBitContext gb; | 
					
						
							|  |  |  |     int flags, i, j, x, y, op; | 
					
						
							|  |  |  |     unsigned char c[3]; | 
					
						
							|  |  |  |     unsigned char *dst; | 
					
						
							| 
									
										
										
										
											2008-07-06 10:01:54 +00:00
										 |  |  |     uint32_t *palette; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     flags = *data++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (flags & 1) { | 
					
						
							| 
									
										
										
										
											2008-07-06 10:01:54 +00:00
										 |  |  |         palette = (uint32_t *)seq->frame.data[1]; | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |         if (data_end - data < 256 * 3) | 
					
						
							|  |  |  |             return AVERROR_INVALIDDATA; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |         for (i = 0; i < 256; i++) { | 
					
						
							|  |  |  |             for (j = 0; j < 3; j++, data++) | 
					
						
							|  |  |  |                 c[j] = (*data << 2) | (*data >> 4); | 
					
						
							| 
									
										
										
										
											2011-11-12 20:19:07 +01:00
										 |  |  |             palette[i] = 0xFF << 24 | AV_RB24(c); | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         seq->frame.palette_has_changed = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (flags & 2) { | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |         if (data_end - data < 128) | 
					
						
							|  |  |  |             return AVERROR_INVALIDDATA; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |         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: | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |                     data = seq_decode_op1(seq, data, data_end, dst); | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |                     break; | 
					
						
							|  |  |  |                 case 2: | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |                     data = seq_decode_op2(seq, data, data_end, dst); | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |                     break; | 
					
						
							|  |  |  |                 case 3: | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |                     data = seq_decode_op3(seq, data, data_end, dst); | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |                 if (!data) | 
					
						
							|  |  |  |                     return AVERROR_INVALIDDATA; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-21 03:11:20 +00:00
										 |  |  | static av_cold int seqvideo_decode_init(AVCodecContext *avctx) | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-04-08 20:24:16 +00:00
										 |  |  |     SeqVideoContext *seq = avctx->priv_data; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     seq->avctx = avctx; | 
					
						
							|  |  |  |     avctx->pix_fmt = PIX_FMT_PAL8; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-02 02:15:15 +02:00
										 |  |  |     avcodec_get_frame_defaults(&seq->frame); | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |     seq->frame.data[0] = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-06 09:58:23 +00:00
										 |  |  | static int seqvideo_decode_frame(AVCodecContext *avctx, | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |                                  void *data, int *data_size, | 
					
						
							| 
									
										
										
										
											2009-04-07 15:59:50 +00:00
										 |  |  |                                  AVPacket *avpkt) | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-07 15:59:50 +00:00
										 |  |  |     const uint8_t *buf = avpkt->data; | 
					
						
							|  |  |  |     int buf_size = avpkt->size; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-08 20:24:16 +00:00
										 |  |  |     SeqVideoContext *seq = avctx->priv_data; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-05 19:48:39 +01:00
										 |  |  |     seq->frame.reference = 3; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  |     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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-30 00:05:47 +02:00
										 |  |  |     if (seqvideo_decode(seq, buf, buf_size)) | 
					
						
							|  |  |  |         return AVERROR_INVALIDDATA; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     *data_size = sizeof(AVFrame); | 
					
						
							|  |  |  |     *(AVFrame *)data = seq->frame; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return buf_size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-07-06 09:58:23 +00:00
										 |  |  | static av_cold int seqvideo_decode_end(AVCodecContext *avctx) | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2007-04-08 20:24:16 +00:00
										 |  |  |     SeqVideoContext *seq = avctx->priv_data; | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (seq->frame.data[0]) | 
					
						
							|  |  |  |         avctx->release_buffer(avctx, &seq->frame); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-25 21:40:11 +00:00
										 |  |  | AVCodec ff_tiertexseqvideo_decoder = { | 
					
						
							| 
									
										
										
										
											2011-07-17 12:54:31 +02:00
										 |  |  |     .name           = "tiertexseqvideo", | 
					
						
							|  |  |  |     .type           = AVMEDIA_TYPE_VIDEO, | 
					
						
							|  |  |  |     .id             = CODEC_ID_TIERTEXSEQVIDEO, | 
					
						
							|  |  |  |     .priv_data_size = sizeof(SeqVideoContext), | 
					
						
							|  |  |  |     .init           = seqvideo_decode_init, | 
					
						
							|  |  |  |     .close          = seqvideo_decode_end, | 
					
						
							|  |  |  |     .decode         = seqvideo_decode_frame, | 
					
						
							|  |  |  |     .capabilities   = CODEC_CAP_DR1, | 
					
						
							| 
									
										
										
										
											2008-06-12 21:50:13 +00:00
										 |  |  |     .long_name = NULL_IF_CONFIG_SMALL("Tiertex Limited SEQ video"), | 
					
						
							| 
									
										
										
										
											2006-10-12 12:02:58 +00:00
										 |  |  | }; |