You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	support for Delphine Software .cin files demuxing / audio and video decoding, by Gregory Montoir %cyx A users P sourceforge P net%
Originally committed as revision 6659 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
		| @@ -65,6 +65,8 @@ OBJS-$(CONFIG_CLJR_ENCODER)            += cljr.o | ||||
| OBJS-$(CONFIG_COOK_DECODER)            += cook.o | ||||
| OBJS-$(CONFIG_CSCD_DECODER)            += cscd.o lzo.o | ||||
| OBJS-$(CONFIG_CYUV_DECODER)            += cyuv.o | ||||
| OBJS-$(CONFIG_DSICINVIDEO_DECODER)     += dsicinav.o | ||||
| OBJS-$(CONFIG_DSICINAUDIO_DECODER)     += dsicinav.o | ||||
| OBJS-$(CONFIG_DVBSUB_DECODER)          += dvbsubdec.o | ||||
| OBJS-$(CONFIG_DVBSUB_ENCODER)          += dvbsub.o | ||||
| OBJS-$(CONFIG_DVDSUB_DECODER)          += dvdsub.o | ||||
|   | ||||
| @@ -548,6 +548,12 @@ void avcodec_register_all(void) | ||||
| #ifdef CONFIG_TARGA_DECODER | ||||
|     register_avcodec(&targa_decoder); | ||||
| #endif //CONFIG_TARGA_DECODER | ||||
| #ifdef CONFIG_DSICINVIDEO_DECODER | ||||
|     register_avcodec(&dsicinvideo_decoder); | ||||
| #endif //CONFIG_DSICINVIDEO_DECODER | ||||
| #ifdef CONFIG_DSICINAUDIO_DECODER | ||||
|     register_avcodec(&dsicinaudio_decoder); | ||||
| #endif //CONFIG_DSICINAUDIO_DECODER | ||||
|  | ||||
| #if defined(CONFIG_AMR_NB) || defined(CONFIG_AMR_NB_FIXED) | ||||
| #ifdef CONFIG_AMR_NB_DECODER | ||||
|   | ||||
| @@ -145,6 +145,7 @@ enum CodecID { | ||||
|     CODEC_ID_VP6, | ||||
|     CODEC_ID_VP6F, | ||||
|     CODEC_ID_TARGA, | ||||
|     CODEC_ID_DSICINVIDEO, | ||||
|  | ||||
|     /* various pcm "codecs" */ | ||||
|     CODEC_ID_PCM_S16LE= 0x10000, | ||||
| @@ -228,6 +229,7 @@ enum CodecID { | ||||
|     CODEC_ID_SMACKAUDIO, | ||||
|     CODEC_ID_QCELP, | ||||
|     CODEC_ID_WAVPACK, | ||||
|     CODEC_ID_DSICINAUDIO, | ||||
|  | ||||
|     /* subtitle codecs */ | ||||
|     CODEC_ID_DVD_SUBTITLE= 0x17000, | ||||
| @@ -2294,6 +2296,8 @@ extern AVCodec cavs_decoder; | ||||
| extern AVCodec vmnc_decoder; | ||||
| extern AVCodec wavpack_decoder; | ||||
| extern AVCodec targa_decoder; | ||||
| extern AVCodec dsicinvideo_decoder; | ||||
| extern AVCodec dsicinaudio_decoder; | ||||
|  | ||||
| /* pcm codecs */ | ||||
| #define PCM_CODEC(id, name) \ | ||||
|   | ||||
							
								
								
									
										362
									
								
								libavcodec/dsicinav.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										362
									
								
								libavcodec/dsicinav.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,362 @@ | ||||
| /* | ||||
|  * Delphine Software International CIN Audio/Video Decoders | ||||
|  * 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 dsicinav.c | ||||
|  * Delphine Software International CIN audio/video decoders | ||||
|  */ | ||||
|  | ||||
| #include "avcodec.h" | ||||
| #include "common.h" | ||||
|  | ||||
|  | ||||
| typedef enum CinVideoBitmapIndex { | ||||
|     CIN_CUR_BMP = 0, /* current */ | ||||
|     CIN_PRE_BMP = 1, /* previous */ | ||||
|     CIN_INT_BMP = 2  /* intermediate */ | ||||
| } CinVideoBitmapIndex; | ||||
|  | ||||
| typedef struct CinVideoContext { | ||||
|     AVCodecContext *avctx; | ||||
|     AVFrame frame; | ||||
|     unsigned int bitmap_size; | ||||
|     uint32_t palette[256]; | ||||
|     uint8_t *bitmap_table[3]; | ||||
| } CinVideoContext; | ||||
|  | ||||
| typedef struct CinAudioContext { | ||||
|     AVCodecContext *avctx; | ||||
|     int initial_decode_frame; | ||||
|     int delta; | ||||
| } CinAudioContext; | ||||
|  | ||||
|  | ||||
| /* table defining a geometric sequence with multiplier = 32767 ^ (1 / 128) */ | ||||
| static const int16_t cinaudio_delta16_table[256] = { | ||||
|          0,      0,      0,      0,      0,      0,      0,      0, | ||||
|          0,      0,      0,      0,      0,      0,      0,      0, | ||||
|          0,      0,      0, -30210, -27853, -25680, -23677, -21829, | ||||
|     -20126, -18556, -17108, -15774, -14543, -13408, -12362, -11398, | ||||
|     -10508,  -9689,  -8933,  -8236,  -7593,  -7001,  -6455,  -5951, | ||||
|      -5487,  -5059,  -4664,  -4300,  -3964,  -3655,  -3370,  -3107, | ||||
|      -2865,  -2641,  -2435,  -2245,  -2070,  -1908,  -1759,  -1622, | ||||
|      -1495,  -1379,  -1271,  -1172,  -1080,   -996,   -918,   -847, | ||||
|       -781,   -720,   -663,   -612,   -564,   -520,   -479,   -442, | ||||
|       -407,   -376,   -346,   -319,   -294,   -271,   -250,   -230, | ||||
|       -212,   -196,   -181,   -166,   -153,   -141,   -130,   -120, | ||||
|       -111,   -102,    -94,    -87,    -80,    -74,    -68,    -62, | ||||
|        -58,    -53,    -49,    -45,    -41,    -38,    -35,    -32, | ||||
|        -30,    -27,    -25,    -23,    -21,    -20,    -18,    -17, | ||||
|        -15,    -14,    -13,    -12,    -11,    -10,     -9,     -8, | ||||
|         -7,     -6,     -5,     -4,     -3,     -2,     -1,      0, | ||||
|          0,      1,      2,      3,      4,      5,      6,      7, | ||||
|          8,      9,     10,     11,     12,     13,     14,     15, | ||||
|         17,     18,     20,     21,     23,     25,     27,     30, | ||||
|         32,     35,     38,     41,     45,     49,     53,     58, | ||||
|         62,     68,     74,     80,     87,     94,    102,    111, | ||||
|        120,    130,    141,    153,    166,    181,    196,    212, | ||||
|        230,    250,    271,    294,    319,    346,    376,    407, | ||||
|        442,    479,    520,    564,    612,    663,    720,    781, | ||||
|        847,    918,    996,   1080,   1172,   1271,   1379,   1495, | ||||
|       1622,   1759,   1908,   2070,   2245,   2435,   2641,   2865, | ||||
|       3107,   3370,   3655,   3964,   4300,   4664,   5059,   5487, | ||||
|       5951,   6455,   7001,   7593,   8236,   8933,   9689,  10508, | ||||
|      11398,  12362,  13408,  14543,  15774,  17108,  18556,  20126, | ||||
|      21829,  23677,  25680,  27853,  30210,      0,      0,      0, | ||||
|          0,      0,      0,      0,      0,      0,      0,      0, | ||||
|          0,      0,      0,      0,      0,      0,      0,      0 | ||||
| }; | ||||
|  | ||||
|  | ||||
| static int cinvideo_decode_init(AVCodecContext *avctx) | ||||
| { | ||||
|     CinVideoContext *cin = (CinVideoContext *)avctx->priv_data; | ||||
|     unsigned int i; | ||||
|  | ||||
|     cin->avctx = avctx; | ||||
|     avctx->pix_fmt = PIX_FMT_PAL8; | ||||
|     avctx->has_b_frames = 0; | ||||
|  | ||||
|     cin->frame.data[0] = NULL; | ||||
|  | ||||
|     cin->bitmap_size = avctx->width * avctx->height; | ||||
|     for (i = 0; i < 3; ++i) { | ||||
|         cin->bitmap_table[i] = av_mallocz(cin->bitmap_size); | ||||
|         if (!cin->bitmap_table[i]) | ||||
|             av_log(avctx, AV_LOG_ERROR, "Can't allocate bitmap buffers.\n"); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static void cin_apply_delta_data(const unsigned char *src, unsigned char *dst, int size) | ||||
| { | ||||
|     while (size--) | ||||
|         *dst++ += *src++; | ||||
| } | ||||
|  | ||||
| static int cin_decode_huffman(const unsigned char *src, int src_size, unsigned char *dst, int dst_size) | ||||
| { | ||||
|     int b, huff_code = 0; | ||||
|     unsigned char huff_code_table[15]; | ||||
|     unsigned char *dst_cur = dst; | ||||
|     unsigned char *dst_end = dst + dst_size; | ||||
|     const unsigned char *src_end = src + src_size; | ||||
|  | ||||
|     memcpy(huff_code_table, src, 15); src += 15; src_size -= 15; | ||||
|  | ||||
|     while (src < src_end) { | ||||
|         huff_code = *src++; | ||||
|         if ((huff_code >> 4) == 15) { | ||||
|             b = huff_code << 4; | ||||
|             huff_code = *src++; | ||||
|             *dst_cur++ = b | (huff_code >> 4); | ||||
|         } else | ||||
|             *dst_cur++ = huff_code_table[huff_code >> 4]; | ||||
|         if (dst_cur >= dst_end) | ||||
|             break; | ||||
|  | ||||
|         huff_code &= 15; | ||||
|         if (huff_code == 15) { | ||||
|             *dst_cur++ = *src++; | ||||
|         } else | ||||
|             *dst_cur++ = huff_code_table[huff_code]; | ||||
|         if (dst_cur >= dst_end) | ||||
|             break; | ||||
|     } | ||||
|  | ||||
|     return dst_cur - dst; | ||||
| } | ||||
|  | ||||
| static void cin_decode_lzss(const unsigned char *src, int src_size, unsigned char *dst, int dst_size) | ||||
| { | ||||
|     uint16_t cmd; | ||||
|     int i, sz, offset, code; | ||||
|     unsigned char *dst_end = dst + dst_size; | ||||
|     const unsigned char *src_end = src + src_size; | ||||
|  | ||||
|     while (src < src_end && dst < dst_end) { | ||||
|         code = *src++; | ||||
|         for (i = 0; i < 8 && src < src_end && dst < dst_end; ++i) { | ||||
|             if (code & (1 << i)) { | ||||
|                 *dst++ = *src++; | ||||
|             } else { | ||||
|                 cmd = LE_16(src); src += 2; | ||||
|                 offset = cmd >> 4; | ||||
|                 sz = (cmd & 0xF) + 2; | ||||
|                 /* don't use memcpy/memmove here as the decoding routine (ab)uses */ | ||||
|                 /* buffer overlappings to repeat bytes in the destination */ | ||||
|                 sz = FFMIN(sz, dst_end - dst); | ||||
|                 while (sz--) { | ||||
|                     *dst = *(dst - offset - 1); | ||||
|                     ++dst; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void cin_decode_rle(const unsigned char *src, int src_size, unsigned char *dst, int dst_size) | ||||
| { | ||||
|     int len, code; | ||||
|     unsigned char *dst_end = dst + dst_size; | ||||
|     const unsigned char *src_end = src + src_size; | ||||
|  | ||||
|     while (src < src_end && dst < dst_end) { | ||||
|         code = *src++; | ||||
|         if (code & 0x80) { | ||||
|             len = code - 0x7F; | ||||
|             memset(dst, *src++, FFMIN(len, dst_end - dst)); | ||||
|         } else { | ||||
|             len = code + 1; | ||||
|             memcpy(dst, src, FFMIN(len, dst_end - dst)); | ||||
|             src += len; | ||||
|         } | ||||
|         dst += len; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int cinvideo_decode_frame(AVCodecContext *avctx, | ||||
|                                  void *data, int *data_size, | ||||
|                                  uint8_t *buf, int buf_size) | ||||
| { | ||||
|     CinVideoContext *cin = (CinVideoContext *)avctx->priv_data; | ||||
|     int i, y, palette_type, palette_colors_count, bitmap_frame_type, bitmap_frame_size; | ||||
|  | ||||
|     cin->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; | ||||
|     if (avctx->reget_buffer(avctx, &cin->frame)) { | ||||
|         av_log(cin->avctx, AV_LOG_ERROR, "delphinecinvideo: reget_buffer() failed to allocate a frame\n"); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     palette_type = buf[0]; | ||||
|     palette_colors_count = buf[1] | (buf[2] << 8); | ||||
|     bitmap_frame_type = buf[3]; | ||||
|     buf += 4; | ||||
|  | ||||
|     bitmap_frame_size = buf_size - 4; | ||||
|  | ||||
|     /* handle palette */ | ||||
|     if (palette_type == 0) { | ||||
|         for (i = 0; i < palette_colors_count; ++i) { | ||||
|             cin->palette[i] = (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||||
|             buf += 3; | ||||
|             bitmap_frame_size -= 3; | ||||
|         } | ||||
|     } else { | ||||
|         for (i = 0; i < palette_colors_count; ++i) { | ||||
|             cin->palette[buf[0]] = (buf[3] << 16) | (buf[2] << 8) | buf[1]; | ||||
|             buf += 4; | ||||
|             bitmap_frame_size -= 4; | ||||
|         } | ||||
|     } | ||||
|     memcpy(cin->frame.data[1], cin->palette, sizeof(cin->palette)); | ||||
|     cin->frame.palette_has_changed = 1; | ||||
|  | ||||
|     /* note: the decoding routines below assumes that surface.width = surface.pitch */ | ||||
|     switch (bitmap_frame_type) { | ||||
|     case 9: | ||||
|         cin_decode_rle(buf, bitmap_frame_size, | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         break; | ||||
|     case 34: | ||||
|         cin_decode_rle(buf, bitmap_frame_size, | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         break; | ||||
|     case 35: | ||||
|         cin_decode_huffman(buf, bitmap_frame_size, | ||||
|           cin->bitmap_table[CIN_INT_BMP], cin->bitmap_size); | ||||
|         cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         break; | ||||
|     case 36: | ||||
|         bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size, | ||||
|           cin->bitmap_table[CIN_INT_BMP], cin->bitmap_size); | ||||
|         cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         break; | ||||
|     case 37: | ||||
|         cin_decode_huffman(buf, bitmap_frame_size, | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         break; | ||||
|     case 38: | ||||
|         cin_decode_lzss(buf, bitmap_frame_size, | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         break; | ||||
|     case 39: | ||||
|         cin_decode_lzss(buf, bitmap_frame_size, | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], | ||||
|           cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     for (y = 0; y < cin->avctx->height; ++y) | ||||
|         memcpy(cin->frame.data[0] + (cin->avctx->height - 1 - y) * cin->frame.linesize[0], | ||||
|           cin->bitmap_table[CIN_CUR_BMP] + y * cin->avctx->width, | ||||
|           cin->avctx->width); | ||||
|  | ||||
|     SWAP(uint8_t *, cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_table[CIN_PRE_BMP]); | ||||
|  | ||||
|     *data_size = sizeof(AVFrame); | ||||
|     *(AVFrame *)data = cin->frame; | ||||
|  | ||||
|     return buf_size; | ||||
| } | ||||
|  | ||||
| static int cinvideo_decode_end(AVCodecContext *avctx) | ||||
| { | ||||
|     CinVideoContext *cin = (CinVideoContext *)avctx->priv_data; | ||||
|     int i; | ||||
|  | ||||
|     if (cin->frame.data[0]) | ||||
|         avctx->release_buffer(avctx, &cin->frame); | ||||
|  | ||||
|     for (i = 0; i < 3; ++i) | ||||
|         av_free(cin->bitmap_table[i]); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int cinaudio_decode_init(AVCodecContext *avctx) | ||||
| { | ||||
|     CinAudioContext *cin = (CinAudioContext *)avctx->priv_data; | ||||
|  | ||||
|     cin->avctx = avctx; | ||||
|     cin->initial_decode_frame = 1; | ||||
|     cin->delta = 0; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int cinaudio_decode_frame(AVCodecContext *avctx, | ||||
|                                  void *data, int *data_size, | ||||
|                                  uint8_t *buf, int buf_size) | ||||
| { | ||||
|     CinAudioContext *cin = (CinAudioContext *)avctx->priv_data; | ||||
|     uint8_t *src = buf; | ||||
|     int16_t *samples = (int16_t *)data; | ||||
|  | ||||
|     if (cin->initial_decode_frame) { | ||||
|         cin->initial_decode_frame = 0; | ||||
|         cin->delta = (int16_t)LE_16(src); src += 2; | ||||
|         *samples++ = cin->delta; | ||||
|         buf_size -= 2; | ||||
|     } | ||||
|     while (buf_size > 0) { | ||||
|         cin->delta += cinaudio_delta16_table[*src++]; | ||||
|         cin->delta = clip(cin->delta, -32768, 32767); | ||||
|         *samples++ = cin->delta; | ||||
|         --buf_size; | ||||
|     } | ||||
|  | ||||
|     *data_size = (uint8_t *)samples - (uint8_t *)data; | ||||
|  | ||||
|     return src - buf; | ||||
| } | ||||
|  | ||||
|  | ||||
| AVCodec dsicinvideo_decoder = { | ||||
|     "dsicinvideo", | ||||
|     CODEC_TYPE_VIDEO, | ||||
|     CODEC_ID_DSICINVIDEO, | ||||
|     sizeof(CinVideoContext), | ||||
|     cinvideo_decode_init, | ||||
|     NULL, | ||||
|     cinvideo_decode_end, | ||||
|     cinvideo_decode_frame, | ||||
|     CODEC_CAP_DR1, | ||||
| }; | ||||
|  | ||||
| AVCodec dsicinaudio_decoder = { | ||||
|     "dsicinaudio", | ||||
|     CODEC_TYPE_AUDIO, | ||||
|     CODEC_ID_DSICINAUDIO, | ||||
|     sizeof(CinAudioContext), | ||||
|     cinaudio_decode_init, | ||||
|     NULL, | ||||
|     NULL, | ||||
|     cinaudio_decode_frame, | ||||
| }; | ||||
| @@ -29,6 +29,7 @@ OBJS-$(CONFIG_AVS_DEMUXER)               += avs.o | ||||
| OBJS-$(CONFIG_CRC_MUXER)                 += crc.o | ||||
| OBJS-$(CONFIG_FRAMECRC_MUXER)            += crc.o | ||||
| OBJS-$(CONFIG_DAUD_DEMUXER)              += daud.o | ||||
| OBJS-$(CONFIG_DSICIN_DEMUXER)            += dsicin.o | ||||
| OBJS-$(CONFIG_DV_DEMUXER)                += dv.o | ||||
| OBJS-$(CONFIG_DV_MUXER)                  += dvenc.o | ||||
| OBJS-$(CONFIG_EA_DEMUXER)                += electronicarts.o | ||||
|   | ||||
| @@ -105,6 +105,9 @@ void av_register_all(void) | ||||
|     av_register_input_format(&dc1394_demuxer); | ||||
| #endif | ||||
| #endif /* CONFIG_DC1394 */ | ||||
| #ifdef CONFIG_DSICIN_DEMUXER | ||||
|     av_register_input_format(&dsicin_demuxer); | ||||
| #endif | ||||
| #ifdef CONFIG_DV1394 | ||||
| #ifdef CONFIG_DV1394_DEMUXER | ||||
|     av_register_input_format(&dv1394_demuxer); | ||||
|   | ||||
| @@ -43,6 +43,7 @@ extern AVOutputFormat crc_muxer; | ||||
| extern AVOutputFormat framecrc_muxer; | ||||
| extern AVInputFormat daud_demuxer; | ||||
| extern AVInputFormat dc1394_demuxer; | ||||
| extern AVInputFormat dsicin_demuxer; | ||||
| extern AVInputFormat dv1394_demuxer; | ||||
| extern AVInputFormat dv_demuxer; | ||||
| extern AVOutputFormat dv_muxer; | ||||
|   | ||||
							
								
								
									
										224
									
								
								libavformat/dsicin.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								libavformat/dsicin.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,224 @@ | ||||
| /* | ||||
|  * Delphine Software International CIN 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 dsicin.c | ||||
|  * Delphine Software International CIN file demuxer | ||||
|  */ | ||||
|  | ||||
| #include "avformat.h" | ||||
|  | ||||
|  | ||||
| typedef struct CinFileHeader { | ||||
|     int video_frame_size; | ||||
|     int video_frame_width; | ||||
|     int video_frame_height; | ||||
|     int audio_frequency; | ||||
|     int audio_bits; | ||||
|     int audio_stereo; | ||||
|     int audio_frame_size; | ||||
| } CinFileHeader; | ||||
|  | ||||
| typedef struct CinFrameHeader { | ||||
|     int audio_frame_type; | ||||
|     int video_frame_type; | ||||
|     int pal_colors_count; | ||||
|     int audio_frame_size; | ||||
|     int video_frame_size; | ||||
| } CinFrameHeader; | ||||
|  | ||||
| typedef struct CinDemuxContext { | ||||
|     int audio_stream_index; | ||||
|     int video_stream_index; | ||||
|     CinFileHeader file_header; | ||||
|     int64_t audio_stream_pts; | ||||
|     int64_t video_stream_pts; | ||||
|     CinFrameHeader frame_header; | ||||
|     int audio_buffer_size; | ||||
| } CinDemuxContext; | ||||
|  | ||||
|  | ||||
| static int cin_probe(AVProbeData *p) | ||||
| { | ||||
|     if (p->buf_size < 18) | ||||
|         return 0; | ||||
|  | ||||
|     /* header starts with this special marker */ | ||||
|     if (LE_32(&p->buf[0]) != 0x55AA0000) | ||||
|         return 0; | ||||
|  | ||||
|     /* for accuracy, check some header field values */ | ||||
|     if (LE_32(&p->buf[12]) != 22050 || p->buf[16] != 16 || p->buf[17] != 0) | ||||
|         return 0; | ||||
|  | ||||
|     return AVPROBE_SCORE_MAX; | ||||
| } | ||||
|  | ||||
| static int cin_read_file_header(CinDemuxContext *cin, ByteIOContext *pb) { | ||||
|     CinFileHeader *hdr = &cin->file_header; | ||||
|  | ||||
|     if (get_le32(pb) != 0x55AA0000) | ||||
|         return AVERROR_INVALIDDATA; | ||||
|  | ||||
|     hdr->video_frame_size   = get_le32(pb); | ||||
|     hdr->video_frame_width  = get_le16(pb); | ||||
|     hdr->video_frame_height = get_le16(pb); | ||||
|     hdr->audio_frequency    = get_le32(pb); | ||||
|     hdr->audio_bits         = get_byte(pb); | ||||
|     hdr->audio_stereo       = get_byte(pb); | ||||
|     hdr->audio_frame_size   = get_le16(pb); | ||||
|  | ||||
|     if (hdr->audio_frequency != 22050 || hdr->audio_bits != 16 || hdr->audio_stereo != 0) | ||||
|         return AVERROR_INVALIDDATA; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int cin_read_header(AVFormatContext *s, AVFormatParameters *ap) | ||||
| { | ||||
|     int rc; | ||||
|     CinDemuxContext *cin = (CinDemuxContext *)s->priv_data; | ||||
|     CinFileHeader *hdr = &cin->file_header; | ||||
|     ByteIOContext *pb = &s->pb; | ||||
|     AVStream *st; | ||||
|  | ||||
|     rc = cin_read_file_header(cin, pb); | ||||
|     if (rc) | ||||
|         return rc; | ||||
|  | ||||
|     cin->video_stream_pts = 0; | ||||
|     cin->audio_stream_pts = 0; | ||||
|     cin->audio_buffer_size = 0; | ||||
|  | ||||
|     /* initialize the video decoder stream */ | ||||
|     st = av_new_stream(s, 0); | ||||
|     if (!st) | ||||
|         return AVERROR_NOMEM; | ||||
|  | ||||
|     av_set_pts_info(st, 32, 1, 12); | ||||
|     cin->video_stream_index = st->index; | ||||
|     st->codec->codec_type = CODEC_TYPE_VIDEO; | ||||
|     st->codec->codec_id = CODEC_ID_DSICINVIDEO; | ||||
|     st->codec->codec_tag = 0;  /* no fourcc */ | ||||
|     st->codec->width = hdr->video_frame_width; | ||||
|     st->codec->height = hdr->video_frame_height; | ||||
|  | ||||
|     /* initialize the audio decoder stream */ | ||||
|     st = av_new_stream(s, 0); | ||||
|     if (!st) | ||||
|         return AVERROR_NOMEM; | ||||
|  | ||||
|     av_set_pts_info(st, 32, 1, 22050); | ||||
|     cin->audio_stream_index = st->index; | ||||
|     st->codec->codec_type = CODEC_TYPE_AUDIO; | ||||
|     st->codec->codec_id = CODEC_ID_DSICINAUDIO; | ||||
|     st->codec->codec_tag = 0;  /* no tag */ | ||||
|     st->codec->channels = 1; | ||||
|     st->codec->sample_rate = 22050; | ||||
|     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 cin_read_frame_header(CinDemuxContext *cin, ByteIOContext *pb) { | ||||
|     CinFrameHeader *hdr = &cin->frame_header; | ||||
|  | ||||
|     hdr->video_frame_type = get_byte(pb); | ||||
|     hdr->audio_frame_type = get_byte(pb); | ||||
|     hdr->pal_colors_count = get_le16(pb); | ||||
|     hdr->video_frame_size = get_le32(pb); | ||||
|     hdr->audio_frame_size = get_le32(pb); | ||||
|  | ||||
|     if (url_feof(pb) || url_ferror(pb)) | ||||
|         return AVERROR_IO; | ||||
|  | ||||
|     if (get_le32(pb) != 0xAA55AA55) | ||||
|         return AVERROR_INVALIDDATA; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int cin_read_packet(AVFormatContext *s, AVPacket *pkt) | ||||
| { | ||||
|     CinDemuxContext *cin = (CinDemuxContext *)s->priv_data; | ||||
|     ByteIOContext *pb = &s->pb; | ||||
|     CinFrameHeader *hdr = &cin->frame_header; | ||||
|     int rc, palette_type, pkt_size; | ||||
|  | ||||
|     if (cin->audio_buffer_size == 0) { | ||||
|         rc = cin_read_frame_header(cin, pb); | ||||
|         if (rc) | ||||
|             return rc; | ||||
|  | ||||
|         if ((int16_t)hdr->pal_colors_count < 0) { | ||||
|             hdr->pal_colors_count = -(int16_t)hdr->pal_colors_count; | ||||
|             palette_type = 1; | ||||
|         } else { | ||||
|             palette_type = 0; | ||||
|         } | ||||
|  | ||||
|         /* palette and video packet */ | ||||
|         pkt_size = (palette_type + 3) * hdr->pal_colors_count + hdr->video_frame_size; | ||||
|  | ||||
|         if (av_new_packet(pkt, 4 + pkt_size)) | ||||
|             return AVERROR_NOMEM; | ||||
|  | ||||
|         pkt->stream_index = cin->video_stream_index; | ||||
|         pkt->pts = cin->video_stream_pts++; | ||||
|  | ||||
|         pkt->data[0] = palette_type; | ||||
|         pkt->data[1] = hdr->pal_colors_count & 0xFF; | ||||
|         pkt->data[2] = hdr->pal_colors_count >> 8; | ||||
|         pkt->data[3] = hdr->video_frame_type; | ||||
|  | ||||
|         if (get_buffer(pb, &pkt->data[4], pkt_size) != pkt_size) | ||||
|             return AVERROR_IO; | ||||
|  | ||||
|         /* sound buffer will be processed on next read_packet() call */ | ||||
|         cin->audio_buffer_size = hdr->audio_frame_size; | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     /* audio packet */ | ||||
|     if (av_new_packet(pkt, cin->audio_buffer_size)) | ||||
|         return AVERROR_NOMEM; | ||||
|  | ||||
|     pkt->stream_index = cin->audio_stream_index; | ||||
|     pkt->pts = cin->audio_stream_pts; | ||||
|     cin->audio_stream_pts += cin->audio_buffer_size * 2 / cin->file_header.audio_frame_size; | ||||
|  | ||||
|     if (get_buffer(pb, pkt->data, cin->audio_buffer_size) != cin->audio_buffer_size) | ||||
|         return AVERROR_IO; | ||||
|  | ||||
|     cin->audio_buffer_size = 0; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| AVInputFormat dsicin_demuxer = { | ||||
|     "dsicin", | ||||
|     "Delphine Software International CIN format", | ||||
|     sizeof(CinDemuxContext), | ||||
|     cin_probe, | ||||
|     cin_read_header, | ||||
|     cin_read_packet, | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user