Originally committed as revision 2195 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -17,7 +17,8 @@ OBJS= common.o utils.o mem.o allcodecs.o \ | |||||
| mpeg12.o mpegaudiodec.o pcm.o simple_idct.o \ | mpeg12.o mpegaudiodec.o pcm.o simple_idct.o \ | ||||
| ratecontrol.o adpcm.o eval.o dv.o error_resilience.o \ | ratecontrol.o adpcm.o eval.o dv.o error_resilience.o \ | ||||
| fft.o mdct.o mace.o huffyuv.o cyuv.o opts.o raw.o h264.o golomb.o \ | fft.o mdct.o mace.o huffyuv.o cyuv.o opts.o raw.o h264.o golomb.o \ | ||||
| vp3.o asv1.o 4xm.o cabac.o ffv1.o ra144.o ra288.o vcr1.o cljr.o | |||||
| vp3.o asv1.o 4xm.o cabac.o ffv1.o ra144.o ra288.o vcr1.o cljr.o \ | |||||
| roqvideo.o dpcm.o interplayvideo.o | |||||
| ifeq ($(AMR_NB),yes) | ifeq ($(AMR_NB),yes) | ||||
| ifeq ($(AMR_NB_FIXED),yes) | ifeq ($(AMR_NB_FIXED),yes) | ||||
| @@ -121,11 +121,15 @@ void avcodec_register_all(void) | |||||
| register_avcodec(&cljr_decoder); | register_avcodec(&cljr_decoder); | ||||
| register_avcodec(&fourxm_decoder); | register_avcodec(&fourxm_decoder); | ||||
| register_avcodec(&mdec_decoder); | register_avcodec(&mdec_decoder); | ||||
| register_avcodec(&roq_decoder); | |||||
| register_avcodec(&interplay_video_decoder); | |||||
| #ifdef CONFIG_AC3 | #ifdef CONFIG_AC3 | ||||
| register_avcodec(&ac3_decoder); | register_avcodec(&ac3_decoder); | ||||
| #endif | #endif | ||||
| register_avcodec(&ra_144_decoder); | register_avcodec(&ra_144_decoder); | ||||
| register_avcodec(&ra_288_decoder); | register_avcodec(&ra_288_decoder); | ||||
| register_avcodec(&roq_dpcm_decoder); | |||||
| register_avcodec(&interplay_dpcm_decoder); | |||||
| #endif /* CONFIG_DECODERS */ | #endif /* CONFIG_DECODERS */ | ||||
| #ifdef AMR_NB | #ifdef AMR_NB | ||||
| @@ -66,6 +66,8 @@ enum CodecID { | |||||
| CODEC_ID_VCR1, | CODEC_ID_VCR1, | ||||
| CODEC_ID_CLJR, | CODEC_ID_CLJR, | ||||
| CODEC_ID_MDEC, | CODEC_ID_MDEC, | ||||
| CODEC_ID_ROQ, | |||||
| CODEC_ID_INTERPLAY_VIDEO, | |||||
| /* various pcm "codecs" */ | /* various pcm "codecs" */ | ||||
| CODEC_ID_PCM_S16LE, | CODEC_ID_PCM_S16LE, | ||||
| @@ -88,6 +90,10 @@ enum CodecID { | |||||
| /* RealAudio codecs*/ | /* RealAudio codecs*/ | ||||
| CODEC_ID_RA_144, | CODEC_ID_RA_144, | ||||
| CODEC_ID_RA_288, | CODEC_ID_RA_288, | ||||
| /* various DPCM codecs */ | |||||
| CODEC_ID_ROQ_DPCM, | |||||
| CODEC_ID_INTERPLAY_DPCM, | |||||
| }; | }; | ||||
| enum CodecType { | enum CodecType { | ||||
| @@ -1347,8 +1353,12 @@ extern AVCodec cljr_decoder; | |||||
| extern AVCodec ffv1_decoder; | extern AVCodec ffv1_decoder; | ||||
| extern AVCodec fourxm_decoder; | extern AVCodec fourxm_decoder; | ||||
| extern AVCodec mdec_decoder; | extern AVCodec mdec_decoder; | ||||
| extern AVCodec roq_decoder; | |||||
| extern AVCodec interplay_video_decoder; | |||||
| extern AVCodec ra_144_decoder; | extern AVCodec ra_144_decoder; | ||||
| extern AVCodec ra_288_decoder; | extern AVCodec ra_288_decoder; | ||||
| extern AVCodec roq_dpcm_decoder; | |||||
| extern AVCodec interplay_dpcm_decoder; | |||||
| /* pcm codecs */ | /* pcm codecs */ | ||||
| #define PCM_CODEC(id, name) \ | #define PCM_CODEC(id, name) \ | ||||
| @@ -0,0 +1,200 @@ | |||||
| /* | |||||
| * Assorted DPCM codecs | |||||
| * Copyright (c) 2003 The ffmpeg Project. | |||||
| * | |||||
| * This library 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 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library 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 this library; if not, write to the Free Software | |||||
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| */ | |||||
| /** | |||||
| * @file: dpcm.c | |||||
| * Assorted DPCM (differential pulse code modulation) audio codecs | |||||
| * by Mike Melanson (melanson@pcisys.net) | |||||
| * for more information on the specific data formats, visit: | |||||
| * http://www.pcisys.net/~melanson/codecs/simpleaudio.html | |||||
| */ | |||||
| #include "avcodec.h" | |||||
| typedef struct DPCMContext { | |||||
| int channels; | |||||
| short roq_square_array[256]; | |||||
| int last_delta[2]; | |||||
| } DPCMContext; | |||||
| #define SATURATE_S16(x) if (x < -32768) x = -32768; \ | |||||
| else if (x > 32767) x = 32767; | |||||
| #define SE_16BIT(x) if (x & 0x8000) x -= 0x10000; | |||||
| #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) | |||||
| #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ | |||||
| (((uint8_t*)(x))[2] << 16) | \ | |||||
| (((uint8_t*)(x))[1] << 8) | \ | |||||
| ((uint8_t*)(x))[0]) | |||||
| static int interplay_delta_table[] = { | |||||
| 0, 1, 2, 3, 4, 5, 6, 7, | |||||
| 8, 9, 10, 11, 12, 13, 14, 15, | |||||
| 16, 17, 18, 19, 20, 21, 22, 23, | |||||
| 24, 25, 26, 27, 28, 29, 30, 31, | |||||
| 32, 33, 34, 35, 36, 37, 38, 39, | |||||
| 40, 41, 42, 43, 47, 51, 56, 61, | |||||
| 66, 72, 79, 86, 94, 102, 112, 122, | |||||
| 133, 145, 158, 173, 189, 206, 225, 245, | |||||
| 267, 292, 318, 348, 379, 414, 452, 493, | |||||
| 538, 587, 640, 699, 763, 832, 908, 991, | |||||
| 1081, 1180, 1288, 1405, 1534, 1673, 1826, 1993, | |||||
| 2175, 2373, 2590, 2826, 3084, 3365, 3672, 4008, | |||||
| 4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, | |||||
| 8794, 9597, 10472, 11428, 12471, 13609, 14851, 16206, | |||||
| 17685, 19298, 21060, 22981, 25078, 27367, 29864, 32589, | |||||
| -29973, -26728, -23186, -19322, -15105, -10503, -5481, -1, | |||||
| 1, 1, 5481, 10503, 15105, 19322, 23186, 26728, | |||||
| 29973, -32589, -29864, -27367, -25078, -22981, -21060, -19298, | |||||
| -17685, -16206, -14851, -13609, -12471, -11428, -10472, -9597, | |||||
| -8794, -8059, -7385, -6767, -6202, -5683, -5208, -4772, | |||||
| -4373, -4008, -3672, -3365, -3084, -2826, -2590, -2373, | |||||
| -2175, -1993, -1826, -1673, -1534, -1405, -1288, -1180, | |||||
| -1081, -991, -908, -832, -763, -699, -640, -587, | |||||
| -538, -493, -452, -414, -379, -348, -318, -292, | |||||
| -267, -245, -225, -206, -189, -173, -158, -145, | |||||
| -133, -122, -112, -102, -94, -86, -79, -72, | |||||
| -66, -61, -56, -51, -47, -43, -42, -41, | |||||
| -40, -39, -38, -37, -36, -35, -34, -33, | |||||
| -32, -31, -30, -29, -28, -27, -26, -25, | |||||
| -24, -23, -22, -21, -20, -19, -18, -17, | |||||
| -16, -15, -14, -13, -12, -11, -10, -9, | |||||
| -8, -7, -6, -5, -4, -3, -2, -1 | |||||
| }; | |||||
| static int dpcm_decode_init(AVCodecContext *avctx) | |||||
| { | |||||
| DPCMContext *s = avctx->priv_data; | |||||
| int i; | |||||
| short square; | |||||
| s->channels = avctx->channels; | |||||
| switch(avctx->codec->id) { | |||||
| case CODEC_ID_ROQ_DPCM: | |||||
| /* initialize square table */ | |||||
| for (i = 0; i < 128; i++) { | |||||
| square = i * i; | |||||
| s->roq_square_array[i] = square; | |||||
| s->roq_square_array[i + 128] = -square; | |||||
| } | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static int dpcm_decode_frame(AVCodecContext *avctx, | |||||
| void *data, int *data_size, | |||||
| uint8_t *buf, int buf_size) | |||||
| { | |||||
| DPCMContext *s = avctx->priv_data; | |||||
| int in, out = 0; | |||||
| int i; | |||||
| int predictor[2]; | |||||
| int channel_number = 0; | |||||
| short *output_samples = data; | |||||
| int sequence_number; | |||||
| switch(avctx->codec->id) { | |||||
| case CODEC_ID_ROQ_DPCM: | |||||
| if (s->channels == 1) | |||||
| predictor[0] = LE_16(&buf[6]); | |||||
| else { | |||||
| predictor[0] = buf[7] << 8; | |||||
| predictor[1] = buf[6] << 8; | |||||
| } | |||||
| SE_16BIT(predictor[0]); | |||||
| SE_16BIT(predictor[1]); | |||||
| /* decode the samples */ | |||||
| for (in = 8, out = 0; in < buf_size; in++, out++) { | |||||
| predictor[channel_number] += s->roq_square_array[buf[in]]; | |||||
| SATURATE_S16(predictor[channel_number]); | |||||
| output_samples[out] = predictor[channel_number]; | |||||
| /* toggle channel */ | |||||
| channel_number ^= s->channels - 1; | |||||
| } | |||||
| break; | |||||
| case CODEC_ID_INTERPLAY_DPCM: | |||||
| in = 0; | |||||
| sequence_number = LE_16(&buf[in]); | |||||
| in += 6; /* skip over the stream mask and stream length */ | |||||
| if (sequence_number == 1) { | |||||
| predictor[0] = LE_16(&buf[in]); | |||||
| in += 2; | |||||
| SE_16BIT(predictor[0]) | |||||
| if (s->channels == 2) { | |||||
| predictor[1] = LE_16(&buf[in]); | |||||
| SE_16BIT(predictor[1]) | |||||
| in += 2; | |||||
| } | |||||
| } else { | |||||
| for (i = 0; i < s->channels; i++) | |||||
| predictor[i] = s->last_delta[i]; | |||||
| } | |||||
| while (in < buf_size) { | |||||
| predictor[channel_number] += interplay_delta_table[buf[in++]]; | |||||
| SATURATE_S16(predictor[channel_number]); | |||||
| output_samples[out++] = predictor[channel_number]; | |||||
| /* toggle channel */ | |||||
| channel_number ^= s->channels - 1; | |||||
| } | |||||
| /* save predictors for next round */ | |||||
| for (i = 0; i < s->channels; i++) | |||||
| s->last_delta[i] = predictor[i]; | |||||
| break; | |||||
| } | |||||
| *data_size = out * sizeof(short); | |||||
| return buf_size; | |||||
| } | |||||
| AVCodec roq_dpcm_decoder = { | |||||
| "roq_dpcm", | |||||
| CODEC_TYPE_AUDIO, | |||||
| CODEC_ID_ROQ_DPCM, | |||||
| sizeof(DPCMContext), | |||||
| dpcm_decode_init, | |||||
| NULL, | |||||
| NULL, | |||||
| dpcm_decode_frame, | |||||
| }; | |||||
| AVCodec interplay_dpcm_decoder = { | |||||
| "interplay_dpcm", | |||||
| CODEC_TYPE_AUDIO, | |||||
| CODEC_ID_INTERPLAY_DPCM, | |||||
| sizeof(DPCMContext), | |||||
| dpcm_decode_init, | |||||
| NULL, | |||||
| NULL, | |||||
| dpcm_decode_frame, | |||||
| }; | |||||
| @@ -0,0 +1,145 @@ | |||||
| /* | |||||
| * Interplay MVE Video Decoder | |||||
| * Copyright (C) 2003 the ffmpeg project | |||||
| * | |||||
| * This library 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 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library 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 this library; if not, write to the Free Software | |||||
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| * | |||||
| */ | |||||
| /** | |||||
| * @file roqvideo.c | |||||
| * Interplay MVE Video Decoder by Mike Melanson | |||||
| * For more information about the Interplay MVE format, visit: | |||||
| * http://www.pcisys.net/~melanson/codecs/ | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <unistd.h> | |||||
| #include "common.h" | |||||
| #include "avcodec.h" | |||||
| #include "dsputil.h" | |||||
| typedef struct IpvideoContext { | |||||
| AVCodecContext *avctx; | |||||
| DSPContext dsp; | |||||
| AVFrame last_frame; | |||||
| AVFrame current_frame; | |||||
| int first_frame; | |||||
| int receiving_decoding_map; | |||||
| unsigned char *decoding_map; | |||||
| int decoding_map_size; | |||||
| unsigned char *buf; | |||||
| int size; | |||||
| } IpvideoContext; | |||||
| static int ipvideo_decode_init(AVCodecContext *avctx) | |||||
| { | |||||
| IpvideoContext *s = avctx->priv_data; | |||||
| s->avctx = avctx; | |||||
| avctx->pix_fmt = PIX_FMT_YUV444P; | |||||
| avctx->has_b_frames = 0; | |||||
| dsputil_init(&s->dsp, avctx); | |||||
| s->first_frame = 1; | |||||
| s->receiving_decoding_map = 1; /* decoding map will be received first */ | |||||
| /* decoding map contains 4 bits of information per 8x8 block */ | |||||
| s->decoding_map_size = avctx->width * avctx->height / (8 * 8 * 2); | |||||
| s->decoding_map = av_malloc(s->decoding_map_size); | |||||
| return 0; | |||||
| } | |||||
| static int ipvideo_decode_frame(AVCodecContext *avctx, | |||||
| void *data, int *data_size, | |||||
| uint8_t *buf, int buf_size) | |||||
| { | |||||
| IpvideoContext *s = avctx->priv_data; | |||||
| if (s->receiving_decoding_map) { | |||||
| /* receiving the decoding map on this iteration */ | |||||
| s->receiving_decoding_map = 0; | |||||
| if (buf_size != s->decoding_map_size) | |||||
| printf (" Interplay video: buf_size != decoding_map_size (%d != %d)\n", | |||||
| buf_size, s->decoding_map_size); | |||||
| else | |||||
| memcpy(s->decoding_map, buf, buf_size); | |||||
| *data_size = 0; | |||||
| *(AVFrame*)data = s->last_frame; | |||||
| } else { | |||||
| /* receiving the compressed video data on this iteration */ | |||||
| s->receiving_decoding_map = 1; | |||||
| s->buf = buf; | |||||
| s->size = buf_size; | |||||
| if (avctx->get_buffer(avctx, &s->current_frame)) { | |||||
| printf (" Interplay Video: get_buffer() failed\n"); | |||||
| return -1; | |||||
| } | |||||
| // ipvideo_decode_frame(s); | |||||
| memset(s->current_frame.data[0], 0x80, s->current_frame.linesize[0] * avctx->height); | |||||
| memset(s->current_frame.data[1], 0x80, s->current_frame.linesize[1] * avctx->height / 4); | |||||
| memset(s->current_frame.data[2], 0x80, s->current_frame.linesize[2] * avctx->height / 4); | |||||
| /* release the last frame if it is allocated */ | |||||
| if (s->first_frame) | |||||
| s->first_frame = 0; | |||||
| else | |||||
| avctx->release_buffer(avctx, &s->last_frame); | |||||
| /* shuffle frames */ | |||||
| s->last_frame = s->current_frame; | |||||
| *data_size = sizeof(AVFrame); | |||||
| *(AVFrame*)data = s->current_frame; | |||||
| } | |||||
| /* always report that the buffer was completely consumed */ | |||||
| return buf_size; | |||||
| } | |||||
| static int ipvideo_decode_end(AVCodecContext *avctx) | |||||
| { | |||||
| IpvideoContext *s = avctx->priv_data; | |||||
| /* release the last frame */ | |||||
| avctx->release_buffer(avctx, &s->last_frame); | |||||
| av_free(s->decoding_map); | |||||
| return 0; | |||||
| } | |||||
| AVCodec interplay_video_decoder = { | |||||
| "interplayvideo", | |||||
| CODEC_TYPE_VIDEO, | |||||
| CODEC_ID_INTERPLAY_VIDEO, | |||||
| sizeof(IpvideoContext), | |||||
| ipvideo_decode_init, | |||||
| NULL, | |||||
| ipvideo_decode_end, | |||||
| ipvideo_decode_frame, | |||||
| CODEC_CAP_DR1, | |||||
| }; | |||||
| @@ -0,0 +1,406 @@ | |||||
| /* | |||||
| * Copyright (C) 2003 the ffmpeg project | |||||
| * | |||||
| * This library 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 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library 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 this library; if not, write to the Free Software | |||||
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| * | |||||
| */ | |||||
| /** | |||||
| * @file roqvideo.c | |||||
| * Id RoQ Video Decoder by Dr. Tim Ferguson | |||||
| * For more information about the Id RoQ format, visit: | |||||
| * http://www.csse.monash.edu.au/~timf/ | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <unistd.h> | |||||
| #include "common.h" | |||||
| #include "avcodec.h" | |||||
| #include "dsputil.h" | |||||
| typedef struct { | |||||
| unsigned char y0, y1, y2, y3, u, v; | |||||
| } roq_cell; | |||||
| typedef struct { | |||||
| int idx[4]; | |||||
| } roq_qcell; | |||||
| typedef struct RoqContext { | |||||
| AVCodecContext *avctx; | |||||
| DSPContext dsp; | |||||
| AVFrame last_frame; | |||||
| AVFrame current_frame; | |||||
| int first_frame; | |||||
| int y_stride; | |||||
| int c_stride; | |||||
| roq_cell cells[256]; | |||||
| roq_qcell qcells[256]; | |||||
| unsigned char *buf; | |||||
| int size; | |||||
| } RoqContext; | |||||
| #define RoQ_INFO 0x1001 | |||||
| #define RoQ_QUAD_CODEBOOK 0x1002 | |||||
| #define RoQ_QUAD_VQ 0x1011 | |||||
| #define RoQ_SOUND_MONO 0x1020 | |||||
| #define RoQ_SOUND_STEREO 0x1021 | |||||
| #define RoQ_ID_MOT 0x00 | |||||
| #define RoQ_ID_FCC 0x01 | |||||
| #define RoQ_ID_SLD 0x02 | |||||
| #define RoQ_ID_CCC 0x03 | |||||
| #define get_byte(in_buffer) *(in_buffer++) | |||||
| #define get_word(in_buffer) ((unsigned short)(in_buffer += 2, \ | |||||
| (in_buffer[-1] << 8 | in_buffer[-2]))) | |||||
| #define get_long(in_buffer) ((unsigned long)(in_buffer += 4, \ | |||||
| (in_buffer[-1] << 24 | in_buffer[-2] << 16 | in_buffer[-3] << 8 | in_buffer[-4]))) | |||||
| static void apply_vector_2x2(RoqContext *ri, int x, int y, roq_cell *cell) | |||||
| { | |||||
| unsigned char *yptr; | |||||
| yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x; | |||||
| *yptr++ = cell->y0; | |||||
| *yptr++ = cell->y1; | |||||
| yptr += (ri->y_stride - 2); | |||||
| *yptr++ = cell->y2; | |||||
| *yptr++ = cell->y3; | |||||
| ri->current_frame.data[1][(y/2) * (ri->c_stride) + x/2] = cell->u; | |||||
| ri->current_frame.data[2][(y/2) * (ri->c_stride) + x/2] = cell->v; | |||||
| } | |||||
| static void apply_vector_4x4(RoqContext *ri, int x, int y, roq_cell *cell) | |||||
| { | |||||
| unsigned long row_inc, c_row_inc; | |||||
| register unsigned char y0, y1, u, v; | |||||
| unsigned char *yptr, *uptr, *vptr; | |||||
| yptr = ri->current_frame.data[0] + (y * ri->y_stride) + x; | |||||
| uptr = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2; | |||||
| vptr = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2; | |||||
| row_inc = ri->y_stride - 4; | |||||
| c_row_inc = (ri->c_stride) - 2; | |||||
| *yptr++ = y0 = cell->y0; *uptr++ = u = cell->u; *vptr++ = v = cell->v; | |||||
| *yptr++ = y0; | |||||
| *yptr++ = y1 = cell->y1; *uptr++ = u; *vptr++ = v; | |||||
| *yptr++ = y1; | |||||
| yptr += row_inc; | |||||
| *yptr++ = y0; | |||||
| *yptr++ = y0; | |||||
| *yptr++ = y1; | |||||
| *yptr++ = y1; | |||||
| yptr += row_inc; uptr += c_row_inc; vptr += c_row_inc; | |||||
| *yptr++ = y0 = cell->y2; *uptr++ = u; *vptr++ = v; | |||||
| *yptr++ = y0; | |||||
| *yptr++ = y1 = cell->y3; *uptr++ = u; *vptr++ = v; | |||||
| *yptr++ = y1; | |||||
| yptr += row_inc; | |||||
| *yptr++ = y0; | |||||
| *yptr++ = y0; | |||||
| *yptr++ = y1; | |||||
| *yptr++ = y1; | |||||
| } | |||||
| static void apply_motion_4x4(RoqContext *ri, int x, int y, unsigned char mv, | |||||
| char mean_x, char mean_y) | |||||
| { | |||||
| int i, mx, my; | |||||
| unsigned char *pa, *pb; | |||||
| mx = x + 8 - (mv >> 4) - mean_x; | |||||
| my = y + 8 - (mv & 0xf) - mean_y; | |||||
| pa = ri->current_frame.data[0] + (y * ri->y_stride) + x; | |||||
| pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx; | |||||
| for(i = 0; i < 4; i++) { | |||||
| pa[0] = pb[0]; | |||||
| pa[1] = pb[1]; | |||||
| pa[2] = pb[2]; | |||||
| pa[3] = pb[3]; | |||||
| pa += ri->y_stride; | |||||
| pb += ri->y_stride; | |||||
| } | |||||
| pa = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2; | |||||
| pb = ri->last_frame.data[1] + (my/2) * (ri->c_stride) + (mx + 1)/2; | |||||
| for(i = 0; i < 2; i++) { | |||||
| pa[0] = pb[0]; | |||||
| pa[1] = pb[1]; | |||||
| pa += ri->c_stride; | |||||
| pb += ri->c_stride; | |||||
| } | |||||
| pa = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2; | |||||
| pb = ri->last_frame.data[2] + (my/2) * (ri->c_stride) + (mx + 1)/2; | |||||
| for(i = 0; i < 2; i++) { | |||||
| pa[0] = pb[0]; | |||||
| pa[1] = pb[1]; | |||||
| pa += ri->c_stride; | |||||
| pb += ri->c_stride; | |||||
| } | |||||
| } | |||||
| static void apply_motion_8x8(RoqContext *ri, int x, int y, | |||||
| unsigned char mv, char mean_x, char mean_y) | |||||
| { | |||||
| int mx, my, i; | |||||
| unsigned char *pa, *pb; | |||||
| mx = x + 8 - (mv >> 4) - mean_x; | |||||
| my = y + 8 - (mv & 0xf) - mean_y; | |||||
| pa = ri->current_frame.data[0] + (y * ri->y_stride) + x; | |||||
| pb = ri->last_frame.data[0] + (my * ri->y_stride) + mx; | |||||
| for(i = 0; i < 8; i++) { | |||||
| pa[0] = pb[0]; | |||||
| pa[1] = pb[1]; | |||||
| pa[2] = pb[2]; | |||||
| pa[3] = pb[3]; | |||||
| pa[4] = pb[4]; | |||||
| pa[5] = pb[5]; | |||||
| pa[6] = pb[6]; | |||||
| pa[7] = pb[7]; | |||||
| pa += ri->y_stride; | |||||
| pb += ri->y_stride; | |||||
| } | |||||
| pa = ri->current_frame.data[1] + (y/2) * (ri->c_stride) + x/2; | |||||
| pb = ri->last_frame.data[1] + (my/2) * (ri->c_stride) + (mx + 1)/2; | |||||
| for(i = 0; i < 4; i++) { | |||||
| pa[0] = pb[0]; | |||||
| pa[1] = pb[1]; | |||||
| pa[2] = pb[2]; | |||||
| pa[3] = pb[3]; | |||||
| pa += ri->c_stride; | |||||
| pb += ri->c_stride; | |||||
| } | |||||
| pa = ri->current_frame.data[2] + (y/2) * (ri->c_stride) + x/2; | |||||
| pb = ri->last_frame.data[2] + (my/2) * (ri->c_stride) + (mx + 1)/2; | |||||
| for(i = 0; i < 4; i++) { | |||||
| pa[0] = pb[0]; | |||||
| pa[1] = pb[1]; | |||||
| pa[2] = pb[2]; | |||||
| pa[3] = pb[3]; | |||||
| pa += ri->c_stride; | |||||
| pb += ri->c_stride; | |||||
| } | |||||
| } | |||||
| static void roqvideo_decode_frame(RoqContext *ri) | |||||
| { | |||||
| unsigned int chunk_id = 0, chunk_arg = 0; | |||||
| unsigned long chunk_size = 0; | |||||
| int i, j, k, nv1, nv2, vqflg = 0, vqflg_pos = -1; | |||||
| int vqid, bpos, xpos, ypos, xp, yp, x, y; | |||||
| int frame_stats[2][4] = {{0},{0}}; | |||||
| roq_qcell *qcell; | |||||
| unsigned char *buf = ri->buf; | |||||
| unsigned char *buf_end = ri->buf + ri->size; | |||||
| while (buf < buf_end) { | |||||
| chunk_id = get_word(buf); | |||||
| chunk_size = get_long(buf); | |||||
| chunk_arg = get_word(buf); | |||||
| if(chunk_id == RoQ_QUAD_VQ) | |||||
| break; | |||||
| if(chunk_id == RoQ_QUAD_CODEBOOK) { | |||||
| if((nv1 = chunk_arg >> 8) == 0) | |||||
| nv1 = 256; | |||||
| if((nv2 = chunk_arg & 0xff) == 0 && nv1 * 6 < chunk_size) | |||||
| nv2 = 256; | |||||
| for(i = 0; i < nv1; i++) { | |||||
| ri->cells[i].y0 = get_byte(buf); | |||||
| ri->cells[i].y1 = get_byte(buf); | |||||
| ri->cells[i].y2 = get_byte(buf); | |||||
| ri->cells[i].y3 = get_byte(buf); | |||||
| ri->cells[i].u = get_byte(buf); | |||||
| ri->cells[i].v = get_byte(buf); | |||||
| } | |||||
| for(i = 0; i < nv2; i++) | |||||
| for(j = 0; j < 4; j++) | |||||
| ri->qcells[i].idx[j] = get_byte(buf); | |||||
| } | |||||
| } | |||||
| bpos = xpos = ypos = 0; | |||||
| while(bpos < chunk_size) { | |||||
| for (yp = ypos; yp < ypos + 16; yp += 8) | |||||
| for (xp = xpos; xp < xpos + 16; xp += 8) { | |||||
| if (vqflg_pos < 0) { | |||||
| vqflg = buf[bpos++]; vqflg |= (buf[bpos++] << 8); | |||||
| vqflg_pos = 7; | |||||
| } | |||||
| vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; | |||||
| frame_stats[0][vqid]++; | |||||
| vqflg_pos--; | |||||
| switch(vqid) { | |||||
| case RoQ_ID_MOT: | |||||
| apply_motion_8x8(ri, xp, yp, 0, 8, 8); | |||||
| break; | |||||
| case RoQ_ID_FCC: | |||||
| apply_motion_8x8(ri, xp, yp, buf[bpos++], chunk_arg >> 8, | |||||
| chunk_arg & 0xff); | |||||
| break; | |||||
| case RoQ_ID_SLD: | |||||
| qcell = ri->qcells + buf[bpos++]; | |||||
| apply_vector_4x4(ri, xp, yp, ri->cells + qcell->idx[0]); | |||||
| apply_vector_4x4(ri, xp+4, yp, ri->cells + qcell->idx[1]); | |||||
| apply_vector_4x4(ri, xp, yp+4, ri->cells + qcell->idx[2]); | |||||
| apply_vector_4x4(ri, xp+4, yp+4, ri->cells + qcell->idx[3]); | |||||
| break; | |||||
| case RoQ_ID_CCC: | |||||
| for (k = 0; k < 4; k++) { | |||||
| x = xp; y = yp; | |||||
| if(k & 0x01) x += 4; | |||||
| if(k & 0x02) y += 4; | |||||
| if (vqflg_pos < 0) { | |||||
| vqflg = buf[bpos++]; | |||||
| vqflg |= (buf[bpos++] << 8); | |||||
| vqflg_pos = 7; | |||||
| } | |||||
| vqid = (vqflg >> (vqflg_pos * 2)) & 0x3; | |||||
| frame_stats[1][vqid]++; | |||||
| vqflg_pos--; | |||||
| switch(vqid) { | |||||
| case RoQ_ID_MOT: | |||||
| apply_motion_4x4(ri, x, y, 0, 8, 8); | |||||
| break; | |||||
| case RoQ_ID_FCC: | |||||
| apply_motion_4x4(ri, x, y, buf[bpos++], | |||||
| chunk_arg >> 8, chunk_arg & 0xff); | |||||
| break; | |||||
| case RoQ_ID_SLD: | |||||
| qcell = ri->qcells + buf[bpos++]; | |||||
| apply_vector_2x2(ri, x, y, ri->cells + qcell->idx[0]); | |||||
| apply_vector_2x2(ri, x+2, y, ri->cells + qcell->idx[1]); | |||||
| apply_vector_2x2(ri, x, y+2, ri->cells + qcell->idx[2]); | |||||
| apply_vector_2x2(ri, x+2, y+2, ri->cells + qcell->idx[3]); | |||||
| break; | |||||
| case RoQ_ID_CCC: | |||||
| apply_vector_2x2(ri, x, y, ri->cells + buf[bpos]); | |||||
| apply_vector_2x2(ri, x+2, y, ri->cells + buf[bpos+1]); | |||||
| apply_vector_2x2(ri, x, y+2, ri->cells + buf[bpos+2]); | |||||
| apply_vector_2x2(ri, x+2, y+2, ri->cells + buf[bpos+3]); | |||||
| bpos += 4; | |||||
| break; | |||||
| } | |||||
| } | |||||
| break; | |||||
| default: | |||||
| printf("Unknown vq code: %d\n", vqid); | |||||
| } | |||||
| } | |||||
| xpos += 16; | |||||
| if (xpos >= ri->avctx->width) { | |||||
| xpos -= ri->avctx->width; | |||||
| ypos += 16; | |||||
| } | |||||
| if(ypos >= ri->avctx->height) | |||||
| break; | |||||
| } | |||||
| } | |||||
| static int roq_decode_init(AVCodecContext *avctx) | |||||
| { | |||||
| RoqContext *s = avctx->priv_data; | |||||
| s->avctx = avctx; | |||||
| s->first_frame = 1; | |||||
| avctx->pix_fmt = PIX_FMT_YUV420P; | |||||
| avctx->has_b_frames = 0; | |||||
| dsputil_init(&s->dsp, avctx); | |||||
| return 0; | |||||
| } | |||||
| static int roq_decode_frame(AVCodecContext *avctx, | |||||
| void *data, int *data_size, | |||||
| uint8_t *buf, int buf_size) | |||||
| { | |||||
| RoqContext *s = avctx->priv_data; | |||||
| *data_size = 0; | |||||
| if (avctx->get_buffer(avctx, &s->current_frame)) { | |||||
| printf (" RoQ: get_buffer() failed\n"); | |||||
| return -1; | |||||
| } | |||||
| s->y_stride = s->current_frame.linesize[0]; | |||||
| s->c_stride = s->current_frame.linesize[1]; | |||||
| s->buf = buf; | |||||
| s->size = buf_size; | |||||
| roqvideo_decode_frame(s); | |||||
| /* release the last frame if it is allocated */ | |||||
| if (s->first_frame) | |||||
| s->first_frame = 0; | |||||
| else | |||||
| avctx->release_buffer(avctx, &s->last_frame); | |||||
| /* shuffle frames */ | |||||
| s->last_frame = s->current_frame; | |||||
| *data_size = sizeof(AVFrame); | |||||
| *(AVFrame*)data = s->current_frame; | |||||
| return buf_size; | |||||
| } | |||||
| static int roq_decode_end(AVCodecContext *avctx) | |||||
| { | |||||
| RoqContext *s = avctx->priv_data; | |||||
| /* release the last frame */ | |||||
| avctx->release_buffer(avctx, &s->last_frame); | |||||
| return 0; | |||||
| } | |||||
| AVCodec roq_decoder = { | |||||
| "roqvideo", | |||||
| CODEC_TYPE_VIDEO, | |||||
| CODEC_ID_ROQ, | |||||
| sizeof(RoqContext), | |||||
| roq_decode_init, | |||||
| NULL, | |||||
| roq_decode_end, | |||||
| roq_decode_frame, | |||||
| CODEC_CAP_DR1, | |||||
| }; | |||||
| @@ -14,7 +14,7 @@ PPOBJS= | |||||
| # mux and demuxes | # mux and demuxes | ||||
| OBJS+=mpeg.o mpegts.o mpegtsenc.o ffm.o crc.o img.o raw.o rm.o \ | OBJS+=mpeg.o mpegts.o mpegtsenc.o ffm.o crc.o img.o raw.o rm.o \ | ||||
| avienc.o avidec.o wav.o swf.o au.o gif.o mov.o mpjpeg.o dvcore.o dv.o \ | avienc.o avidec.o wav.o swf.o au.o gif.o mov.o mpjpeg.o dvcore.o dv.o \ | ||||
| yuv4mpeg.o 4xm.o flvenc.o flvdec.o movenc.o psxstr.o | |||||
| yuv4mpeg.o 4xm.o flvenc.o flvdec.o movenc.o psxstr.o idroq.o ipmovie.o | |||||
| ifeq ($(CONFIG_RISKY),yes) | ifeq ($(CONFIG_RISKY),yes) | ||||
| OBJS+= asf.o | OBJS+= asf.o | ||||
| @@ -52,6 +52,8 @@ void av_register_all(void) | |||||
| flvenc_init(); | flvenc_init(); | ||||
| flvdec_init(); | flvdec_init(); | ||||
| str_init(); | str_init(); | ||||
| roq_init(); | |||||
| ipmovie_init(); | |||||
| #ifdef AMR_NB | #ifdef AMR_NB | ||||
| amr_init(); | amr_init(); | ||||
| @@ -383,6 +383,12 @@ int fourxm_init(void); | |||||
| /* psxstr.c */ | /* psxstr.c */ | ||||
| int str_init(void); | int str_init(void); | ||||
| /* idroq.c */ | |||||
| int roq_init(void); | |||||
| /* ipmovie.c */ | |||||
| int ipmovie_init(void); | |||||
| #include "rtp.h" | #include "rtp.h" | ||||
| #include "rtsp.h" | #include "rtsp.h" | ||||
| @@ -0,0 +1,299 @@ | |||||
| /* | |||||
| * Id RoQ (.roq) File Demuxer | |||||
| * Copyright (c) 2003 The ffmpeg Project | |||||
| * | |||||
| * This library 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 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library 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 this library; if not, write to the Free Software | |||||
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| */ | |||||
| /** | |||||
| * @file idroq.c | |||||
| * Id RoQ format file demuxer | |||||
| * by Mike Melanson (melanson@pcisys.net) | |||||
| * for more information on the .roq file format, visit: | |||||
| * http://www.csse.monash.edu.au/~timf/ | |||||
| */ | |||||
| #include "avformat.h" | |||||
| #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) | |||||
| #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ | |||||
| (((uint8_t*)(x))[2] << 16) | \ | |||||
| (((uint8_t*)(x))[1] << 8) | \ | |||||
| ((uint8_t*)(x))[0]) | |||||
| #define RoQ_MAGIC_NUMBER 0x1084 | |||||
| #define RoQ_CHUNK_PREAMBLE_SIZE 8 | |||||
| #define RoQ_AUDIO_SAMPLE_RATE 22050 | |||||
| #define RoQ_CHUNKS_TO_SCAN 30 | |||||
| #define RoQ_INFO 0x1001 | |||||
| #define RoQ_QUAD_CODEBOOK 0x1002 | |||||
| #define RoQ_QUAD_VQ 0x1011 | |||||
| #define RoQ_SOUND_MONO 0x1020 | |||||
| #define RoQ_SOUND_STEREO 0x1021 | |||||
| typedef struct RoqDemuxContext { | |||||
| int width; | |||||
| int height; | |||||
| int audio_channels; | |||||
| int framerate; | |||||
| int frame_pts_inc; | |||||
| int video_stream_index; | |||||
| int audio_stream_index; | |||||
| int64_t video_pts; | |||||
| unsigned int audio_frame_count; | |||||
| } RoqDemuxContext; | |||||
| static int roq_probe(AVProbeData *p) | |||||
| { | |||||
| if ((LE_16(&p->buf[0]) != RoQ_MAGIC_NUMBER) || | |||||
| (LE_32(&p->buf[2]) != 0xFFFFFFFF)) | |||||
| return 0; | |||||
| return AVPROBE_SCORE_MAX; | |||||
| } | |||||
| static int roq_read_header(AVFormatContext *s, | |||||
| AVFormatParameters *ap) | |||||
| { | |||||
| RoqDemuxContext *roq = s->priv_data; | |||||
| ByteIOContext *pb = &s->pb; | |||||
| AVStream *st; | |||||
| unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; | |||||
| int i; | |||||
| unsigned int chunk_size; | |||||
| unsigned int chunk_type; | |||||
| /* get the main header */ | |||||
| if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != | |||||
| RoQ_CHUNK_PREAMBLE_SIZE) | |||||
| return AVERROR_IO; | |||||
| roq->framerate = LE_16(&preamble[6]); | |||||
| roq->frame_pts_inc = 90000 / roq->framerate; | |||||
| /* set the pts reference (1 pts = 1/90000) */ | |||||
| s->pts_num = 1; | |||||
| s->pts_den = 90000; | |||||
| /* init private context parameters */ | |||||
| roq->width = roq->height = roq->audio_channels = roq->video_pts = | |||||
| roq->audio_frame_count = 0; | |||||
| /* scan the first n chunks searching for A/V parameters */ | |||||
| for (i = 0; i < RoQ_CHUNKS_TO_SCAN; i++) { | |||||
| if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != | |||||
| RoQ_CHUNK_PREAMBLE_SIZE) | |||||
| return AVERROR_IO; | |||||
| chunk_type = LE_16(&preamble[0]); | |||||
| chunk_size = LE_32(&preamble[2]); | |||||
| switch (chunk_type) { | |||||
| case RoQ_INFO: | |||||
| /* fetch the width and height; reuse the preamble bytes */ | |||||
| if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != | |||||
| RoQ_CHUNK_PREAMBLE_SIZE) | |||||
| return AVERROR_IO; | |||||
| roq->width = LE_16(&preamble[0]); | |||||
| roq->height = LE_16(&preamble[2]); | |||||
| break; | |||||
| case RoQ_QUAD_CODEBOOK: | |||||
| case RoQ_QUAD_VQ: | |||||
| /* ignore during this scan */ | |||||
| url_fseek(pb, chunk_size, SEEK_CUR); | |||||
| break; | |||||
| case RoQ_SOUND_MONO: | |||||
| roq->audio_channels = 1; | |||||
| url_fseek(pb, chunk_size, SEEK_CUR); | |||||
| break; | |||||
| case RoQ_SOUND_STEREO: | |||||
| roq->audio_channels = 2; | |||||
| url_fseek(pb, chunk_size, SEEK_CUR); | |||||
| break; | |||||
| default: | |||||
| printf (" unknown RoQ chunk type (%04X)\n", LE_16(&preamble[0])); | |||||
| return AVERROR_INVALIDDATA; | |||||
| break; | |||||
| } | |||||
| /* if all necessary parameters have been gathered, exit early */ | |||||
| if ((roq->width && roq->height) && roq->audio_channels) | |||||
| break; | |||||
| } | |||||
| /* seek back to the first chunk */ | |||||
| url_fseek(pb, RoQ_CHUNK_PREAMBLE_SIZE, SEEK_SET); | |||||
| /* initialize the decoders */ | |||||
| st = av_new_stream(s, 0); | |||||
| if (!st) | |||||
| return AVERROR_NOMEM; | |||||
| roq->video_stream_index = st->index; | |||||
| st->codec.codec_type = CODEC_TYPE_VIDEO; | |||||
| st->codec.codec_id = CODEC_ID_ROQ; | |||||
| st->codec.codec_tag = 0; /* no fourcc */ | |||||
| st->codec.width = roq->width; | |||||
| st->codec.height = roq->height; | |||||
| if (roq->audio_channels) { | |||||
| st = av_new_stream(s, 0); | |||||
| if (!st) | |||||
| return AVERROR_NOMEM; | |||||
| roq->audio_stream_index = st->index; | |||||
| st->codec.codec_type = CODEC_TYPE_AUDIO; | |||||
| st->codec.codec_id = CODEC_ID_ROQ_DPCM; | |||||
| st->codec.codec_tag = 0; /* no tag */ | |||||
| st->codec.channels = roq->audio_channels; | |||||
| st->codec.sample_rate = RoQ_AUDIO_SAMPLE_RATE; | |||||
| st->codec.bits_per_sample = 16; | |||||
| st->codec.bit_rate = st->codec.channels * st->codec.sample_rate * | |||||
| st->codec.bits_per_sample; | |||||
| st->codec.block_align = st->codec.channels * st->codec.bits_per_sample; | |||||
| } | |||||
| printf (" video is %d x %d, audio is %d channels\n", | |||||
| roq->width, roq->height, roq->audio_channels); | |||||
| return 0; | |||||
| } | |||||
| static int roq_read_packet(AVFormatContext *s, | |||||
| AVPacket *pkt) | |||||
| { | |||||
| RoqDemuxContext *roq = s->priv_data; | |||||
| ByteIOContext *pb = &s->pb; | |||||
| int ret = 0; | |||||
| unsigned int chunk_size; | |||||
| unsigned int chunk_type; | |||||
| unsigned int codebook_size; | |||||
| unsigned char preamble[RoQ_CHUNK_PREAMBLE_SIZE]; | |||||
| int packet_read = 0; | |||||
| offset_t codebook_offset; | |||||
| while (!packet_read) { | |||||
| if (url_feof(&s->pb)) | |||||
| return -EIO; | |||||
| /* get the next chunk preamble */ | |||||
| if ((ret = get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE)) != | |||||
| RoQ_CHUNK_PREAMBLE_SIZE) | |||||
| return -EIO; | |||||
| chunk_type = LE_16(&preamble[0]); | |||||
| chunk_size = LE_32(&preamble[2]); | |||||
| switch (chunk_type) { | |||||
| case RoQ_INFO: | |||||
| /* don't care about this chunk anymore */ | |||||
| url_fseek(pb, RoQ_CHUNK_PREAMBLE_SIZE, SEEK_CUR); | |||||
| break; | |||||
| case RoQ_QUAD_CODEBOOK: | |||||
| /* packet needs to contain both this codebook and next VQ chunk */ | |||||
| codebook_offset = url_ftell(pb) - RoQ_CHUNK_PREAMBLE_SIZE; | |||||
| codebook_size = chunk_size; | |||||
| url_fseek(pb, codebook_size, SEEK_CUR); | |||||
| if (get_buffer(pb, preamble, RoQ_CHUNK_PREAMBLE_SIZE) != | |||||
| RoQ_CHUNK_PREAMBLE_SIZE) | |||||
| return -EIO; | |||||
| chunk_size = LE_32(&preamble[2]) + RoQ_CHUNK_PREAMBLE_SIZE * 2 + | |||||
| codebook_size; | |||||
| /* rewind */ | |||||
| url_fseek(pb, codebook_offset, SEEK_SET); | |||||
| /* load up the packet */ | |||||
| if (av_new_packet(pkt, chunk_size)) | |||||
| return -EIO; | |||||
| pkt->stream_index = roq->video_stream_index; | |||||
| pkt->pts = roq->video_pts; | |||||
| ret = get_buffer(pb, pkt->data, chunk_size); | |||||
| if (ret != chunk_size) | |||||
| ret = -EIO; | |||||
| roq->video_pts += roq->frame_pts_inc; | |||||
| packet_read = 1; | |||||
| break; | |||||
| case RoQ_SOUND_MONO: | |||||
| case RoQ_SOUND_STEREO: | |||||
| case RoQ_QUAD_VQ: | |||||
| /* load up the packet */ | |||||
| if (av_new_packet(pkt, chunk_size + RoQ_CHUNK_PREAMBLE_SIZE)) | |||||
| return -EIO; | |||||
| /* copy over preamble */ | |||||
| memcpy(pkt->data, preamble, RoQ_CHUNK_PREAMBLE_SIZE); | |||||
| if (chunk_type == RoQ_QUAD_VQ) { | |||||
| pkt->stream_index = roq->video_stream_index; | |||||
| pkt->pts = roq->video_pts; | |||||
| roq->video_pts += roq->frame_pts_inc; | |||||
| } else { | |||||
| pkt->stream_index = roq->audio_stream_index; | |||||
| pkt->pts = roq->audio_frame_count; | |||||
| pkt->pts *= 90000; | |||||
| pkt->pts /= RoQ_AUDIO_SAMPLE_RATE; | |||||
| roq->audio_frame_count += (chunk_size / roq->audio_channels); | |||||
| } | |||||
| ret = get_buffer(pb, pkt->data, chunk_size); | |||||
| if (ret != chunk_size) | |||||
| ret = -EIO; | |||||
| packet_read = 1; | |||||
| break; | |||||
| default: | |||||
| printf (" unknown RoQ chunk (%04X)\n", chunk_type); | |||||
| return AVERROR_INVALIDDATA; | |||||
| break; | |||||
| } | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| static int roq_read_close(AVFormatContext *s) | |||||
| { | |||||
| // RoqDemuxContext *roq = (RoqDemuxContext *)s->priv_data; | |||||
| return 0; | |||||
| } | |||||
| static AVInputFormat roq_iformat = { | |||||
| "RoQ", | |||||
| "Id RoQ format", | |||||
| sizeof(RoqDemuxContext), | |||||
| roq_probe, | |||||
| roq_read_header, | |||||
| roq_read_packet, | |||||
| roq_read_close, | |||||
| }; | |||||
| int roq_init(void) | |||||
| { | |||||
| av_register_input_format(&roq_iformat); | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,618 @@ | |||||
| /* | |||||
| * Interplay MVE File Demuxer | |||||
| * Copyright (c) 2003 The ffmpeg Project | |||||
| * | |||||
| * This library 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 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library 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 this library; if not, write to the Free Software | |||||
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| */ | |||||
| /** | |||||
| * @file ipmovie.c | |||||
| * Interplay MVE file demuxer | |||||
| * by Mike Melanson (melanson@pcisys.net) | |||||
| * For more information regarding the Interplay MVE file format, visit: | |||||
| * http://www.pcisys.net/~melanson/codecs/ | |||||
| * The aforementioned site also contains a command line utility for parsing | |||||
| * IP MVE files so that you can get a good idea of the typical structure of | |||||
| * such files. This demuxer is not the best example to use if you are trying | |||||
| * to write your own as it uses a rather roundabout approach for splitting | |||||
| * up and sending out the chunks. | |||||
| */ | |||||
| #include "avformat.h" | |||||
| /* debugging support: #define DEBUG_IPMOVIE as non-zero to see extremely | |||||
| * verbose information about the demux process */ | |||||
| #define DEBUG_IPMOVIE 0 | |||||
| #if DEBUG_IPMOVIE | |||||
| #define debug_ipmovie printf | |||||
| #else | |||||
| static inline void debug_ipmovie(const char *format, ...) { } | |||||
| #endif | |||||
| #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) | |||||
| #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ | |||||
| (((uint8_t*)(x))[2] << 16) | \ | |||||
| (((uint8_t*)(x))[1] << 8) | \ | |||||
| ((uint8_t*)(x))[0]) | |||||
| #define IPMOVIE_SIGNATURE "Interplay MVE File\x1A\0" | |||||
| #define IPMOVIE_SIGNATURE_SIZE 20 | |||||
| #define CHUNK_PREAMBLE_SIZE 4 | |||||
| #define OPCODE_PREAMBLE_SIZE 4 | |||||
| #define CHUNK_INIT_AUDIO 0x0000 | |||||
| #define CHUNK_AUDIO_ONLY 0x0001 | |||||
| #define CHUNK_INIT_VIDEO 0x0002 | |||||
| #define CHUNK_VIDEO 0x0003 | |||||
| #define CHUNK_SHUTDOWN 0x0004 | |||||
| #define CHUNK_END 0x0005 | |||||
| /* these last types are used internally */ | |||||
| #define CHUNK_DONE 0xFFFC | |||||
| #define CHUNK_NOMEM 0xFFFD | |||||
| #define CHUNK_EOF 0xFFFE | |||||
| #define CHUNK_BAD 0xFFFF | |||||
| #define OPCODE_END_OF_STREAM 0x00 | |||||
| #define OPCODE_END_OF_CHUNK 0x01 | |||||
| #define OPCODE_CREATE_TIMER 0x02 | |||||
| #define OPCODE_INIT_AUDIO_BUFFERS 0x03 | |||||
| #define OPCODE_START_STOP_AUDIO 0x04 | |||||
| #define OPCODE_INIT_VIDEO_BUFFERS 0x05 | |||||
| #define OPCODE_UNKNOWN_06 0x06 | |||||
| #define OPCODE_SEND_BUFFER 0x07 | |||||
| #define OPCODE_AUDIO_FRAME 0x08 | |||||
| #define OPCODE_SILENCE_FRAME 0x09 | |||||
| #define OPCODE_INIT_VIDEO_MODE 0x0A | |||||
| #define OPCODE_CREATE_GRADIENT 0x0B | |||||
| #define OPCODE_SET_PALETTE 0x0C | |||||
| #define OPCODE_SET_PALETTE_COMPRESSED 0x0D | |||||
| #define OPCODE_UNKNOWN_0E 0x0E | |||||
| #define OPCODE_SET_DECODING_MAP 0x0F | |||||
| #define OPCODE_UNKNOWN_10 0x10 | |||||
| #define OPCODE_VIDEO_DATA 0x11 | |||||
| #define OPCODE_UNKNOWN_12 0x12 | |||||
| #define OPCODE_UNKNOWN_13 0x13 | |||||
| #define OPCODE_UNKNOWN_14 0x14 | |||||
| #define OPCODE_UNKNOWN_15 0x15 | |||||
| #define PALETTE_COUNT 256 | |||||
| typedef struct IPMVEContext { | |||||
| unsigned char *buf; | |||||
| int buf_size; | |||||
| int fps; | |||||
| int frame_pts_inc; | |||||
| unsigned int video_width; | |||||
| unsigned int video_height; | |||||
| int64_t video_pts; | |||||
| unsigned int audio_bits; | |||||
| unsigned int audio_channels; | |||||
| unsigned int audio_sample_rate; | |||||
| unsigned int audio_type; | |||||
| unsigned int audio_frame_count; | |||||
| int video_stream_index; | |||||
| int audio_stream_index; | |||||
| offset_t audio_chunk_offset; | |||||
| int audio_chunk_size; | |||||
| offset_t video_chunk_offset; | |||||
| int video_chunk_size; | |||||
| offset_t decode_map_chunk_offset; | |||||
| int decode_map_chunk_size; | |||||
| offset_t next_chunk_offset; | |||||
| } IPMVEContext; | |||||
| static int load_ipmovie_packet(IPMVEContext *s, ByteIOContext *pb, | |||||
| AVPacket *pkt) { | |||||
| int chunk_type; | |||||
| int64_t audio_pts = 0; | |||||
| if (s->audio_chunk_offset) { | |||||
| url_fseek(pb, s->audio_chunk_offset, SEEK_SET); | |||||
| s->audio_chunk_offset = 0; | |||||
| /* figure out the audio pts */ | |||||
| audio_pts = 90000; | |||||
| audio_pts *= s->audio_frame_count; | |||||
| audio_pts /= s->audio_sample_rate; | |||||
| if (av_new_packet(pkt, s->audio_chunk_size)) | |||||
| return CHUNK_NOMEM; | |||||
| pkt->stream_index = s->audio_stream_index; | |||||
| pkt->pts = audio_pts; | |||||
| if (get_buffer(pb, pkt->data, s->audio_chunk_size) != | |||||
| s->audio_chunk_size) { | |||||
| av_free_packet(pkt); | |||||
| return CHUNK_EOF; | |||||
| } | |||||
| /* audio frame maintenance */ | |||||
| if (s->audio_type != CODEC_ID_INTERPLAY_DPCM) | |||||
| s->audio_frame_count += | |||||
| (s->audio_chunk_size / s->audio_channels / (s->audio_bits / 8)); | |||||
| else | |||||
| s->audio_frame_count += | |||||
| (s->audio_chunk_size - 6) / s->audio_channels; | |||||
| debug_ipmovie("sending audio frame with pts %lld (%d audio frames)\n", | |||||
| audio_pts, s->audio_frame_count); | |||||
| chunk_type = CHUNK_VIDEO; | |||||
| } else if (s->decode_map_chunk_offset) { | |||||
| url_fseek(pb, s->decode_map_chunk_offset, SEEK_SET); | |||||
| s->decode_map_chunk_offset = 0; | |||||
| if (av_new_packet(pkt, s->decode_map_chunk_size)) | |||||
| return CHUNK_NOMEM; | |||||
| pkt->stream_index = s->video_stream_index; | |||||
| pkt->pts = s->video_pts; | |||||
| if (get_buffer(pb, pkt->data, s->decode_map_chunk_size) != | |||||
| s->decode_map_chunk_size) { | |||||
| av_free_packet(pkt); | |||||
| return CHUNK_EOF; | |||||
| } | |||||
| chunk_type = CHUNK_VIDEO; | |||||
| } else if (s->video_chunk_offset) { | |||||
| url_fseek(pb, s->video_chunk_offset, SEEK_SET); | |||||
| s->video_chunk_offset = 0; | |||||
| if (av_new_packet(pkt, s->video_chunk_size)) | |||||
| return CHUNK_NOMEM; | |||||
| pkt->stream_index = s->video_stream_index; | |||||
| pkt->pts = s->video_pts; | |||||
| if (get_buffer(pb, pkt->data, s->video_chunk_size) != | |||||
| s->video_chunk_size) { | |||||
| av_free_packet(pkt); | |||||
| return CHUNK_EOF; | |||||
| } | |||||
| s->video_pts += s->frame_pts_inc; | |||||
| chunk_type = CHUNK_VIDEO; | |||||
| } else { | |||||
| url_fseek(pb, s->next_chunk_offset, SEEK_SET); | |||||
| chunk_type = CHUNK_DONE; | |||||
| } | |||||
| return chunk_type; | |||||
| } | |||||
| /* This function loads and processes a single chunk in an IP movie file. | |||||
| * It returns the type of chunk that was processed. */ | |||||
| static int process_ipmovie_chunk(IPMVEContext *s, ByteIOContext *pb, | |||||
| AVPacket *pkt) | |||||
| { | |||||
| unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE]; | |||||
| int chunk_type; | |||||
| int chunk_size; | |||||
| unsigned char opcode_preamble[OPCODE_PREAMBLE_SIZE]; | |||||
| unsigned char opcode_type; | |||||
| unsigned char opcode_version; | |||||
| int opcode_size; | |||||
| unsigned char scratch[1024]; | |||||
| int j; | |||||
| int first_color, last_color; | |||||
| int audio_flags; | |||||
| /* see if there are any pending packets */ | |||||
| chunk_type = load_ipmovie_packet(s, pb, pkt); | |||||
| if ((chunk_type == CHUNK_VIDEO) && (chunk_type != CHUNK_DONE)) | |||||
| return chunk_type; | |||||
| /* read the next chunk, wherever the file happens to be pointing */ | |||||
| if (url_feof(pb)) | |||||
| return CHUNK_EOF; | |||||
| if (get_buffer(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) != | |||||
| CHUNK_PREAMBLE_SIZE) | |||||
| return CHUNK_BAD; | |||||
| chunk_size = LE_16(&chunk_preamble[0]); | |||||
| chunk_type = LE_16(&chunk_preamble[2]); | |||||
| debug_ipmovie("chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size); | |||||
| switch (chunk_type) { | |||||
| case CHUNK_INIT_AUDIO: | |||||
| debug_ipmovie("initialize audio\n"); | |||||
| break; | |||||
| case CHUNK_AUDIO_ONLY: | |||||
| debug_ipmovie("audio only\n"); | |||||
| break; | |||||
| case CHUNK_INIT_VIDEO: | |||||
| debug_ipmovie("initialize video\n"); | |||||
| break; | |||||
| case CHUNK_VIDEO: | |||||
| debug_ipmovie("video (and audio)\n"); | |||||
| break; | |||||
| case CHUNK_SHUTDOWN: | |||||
| debug_ipmovie("shutdown\n"); | |||||
| break; | |||||
| case CHUNK_END: | |||||
| debug_ipmovie("end\n"); | |||||
| break; | |||||
| default: | |||||
| debug_ipmovie("invalid chunk\n"); | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) { | |||||
| /* read the next chunk, wherever the file happens to be pointing */ | |||||
| if (url_feof(pb)) { | |||||
| chunk_type = CHUNK_EOF; | |||||
| break; | |||||
| } | |||||
| if (get_buffer(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) != | |||||
| CHUNK_PREAMBLE_SIZE) { | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| opcode_size = LE_16(&opcode_preamble[0]); | |||||
| opcode_type = opcode_preamble[2]; | |||||
| opcode_version = opcode_preamble[3]; | |||||
| chunk_size -= OPCODE_PREAMBLE_SIZE; | |||||
| chunk_size -= opcode_size; | |||||
| if (chunk_size < 0) { | |||||
| debug_ipmovie("chunk_size countdown just went negative\n"); | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| debug_ipmovie(" opcode type %02X, version %d, 0x%04X bytes: ", | |||||
| opcode_type, opcode_version, opcode_size); | |||||
| switch (opcode_type) { | |||||
| case OPCODE_END_OF_STREAM: | |||||
| debug_ipmovie("end of stream\n"); | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_END_OF_CHUNK: | |||||
| debug_ipmovie("end of chunk\n"); | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_CREATE_TIMER: | |||||
| debug_ipmovie("create timer\n"); | |||||
| if ((opcode_version > 0) || (opcode_size > 6)) { | |||||
| debug_ipmovie("bad create_timer opcode\n"); | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| if (get_buffer(pb, scratch, opcode_size) != | |||||
| opcode_size) { | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| s->fps = 1000000 / (LE_32(&scratch[0]) * LE_16(&scratch[4])); | |||||
| s->fps++; /* above calculation usually yields 14.9; we need 15 */ | |||||
| s->frame_pts_inc = 90000 / s->fps; | |||||
| debug_ipmovie("%d frames/second (timer div = %d, subdiv = %d)\n", | |||||
| s->fps, LE_32(&scratch[0]), LE_16(&scratch[4])); | |||||
| break; | |||||
| case OPCODE_INIT_AUDIO_BUFFERS: | |||||
| debug_ipmovie("initialize audio buffers\n"); | |||||
| if ((opcode_version > 1) || (opcode_size > 10)) { | |||||
| debug_ipmovie("bad init_audio_buffers opcode\n"); | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| if (get_buffer(pb, scratch, opcode_size) != | |||||
| opcode_size) { | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| s->audio_sample_rate = LE_16(&scratch[4]); | |||||
| audio_flags = LE_16(&scratch[2]); | |||||
| /* bit 0 of the flags: 0 = mono, 1 = stereo */ | |||||
| s->audio_channels = (audio_flags & 1) + 1; | |||||
| /* bit 1 of the flags: 0 = 8 bit, 1 = 16 bit */ | |||||
| s->audio_bits = (((audio_flags >> 1) & 1) + 1) * 8; | |||||
| /* bit 2 indicates compressed audio in version 1 opcode */ | |||||
| if ((opcode_version == 1) && (audio_flags & 0x4)) | |||||
| s->audio_type = CODEC_ID_INTERPLAY_DPCM; | |||||
| else if (s->audio_bits == 16) | |||||
| s->audio_type = CODEC_ID_PCM_S16LE; | |||||
| else | |||||
| s->audio_type = CODEC_ID_PCM_U8; | |||||
| debug_ipmovie("audio: %d bits, %d Hz, %s, %s format\n", | |||||
| s->audio_bits, | |||||
| s->audio_sample_rate, | |||||
| (s->audio_channels == 2) ? "stereo" : "mono", | |||||
| (s->audio_type == CODEC_ID_INTERPLAY_DPCM) ? | |||||
| "Interplay audio" : "PCM"); | |||||
| break; | |||||
| case OPCODE_START_STOP_AUDIO: | |||||
| debug_ipmovie("start/stop audio\n"); | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_INIT_VIDEO_BUFFERS: | |||||
| debug_ipmovie("initialize video buffers\n"); | |||||
| if ((opcode_version > 2) || (opcode_size > 8)) { | |||||
| debug_ipmovie("bad init_video_buffers opcode\n"); | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| if (get_buffer(pb, scratch, opcode_size) != | |||||
| opcode_size) { | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| s->video_width = LE_16(&scratch[0]) * 8; | |||||
| s->video_height = LE_16(&scratch[2]) * 8; | |||||
| debug_ipmovie("video resolution: %d x %d\n", | |||||
| s->video_width, s->video_height); | |||||
| break; | |||||
| case OPCODE_UNKNOWN_06: | |||||
| case OPCODE_UNKNOWN_0E: | |||||
| case OPCODE_UNKNOWN_10: | |||||
| case OPCODE_UNKNOWN_12: | |||||
| case OPCODE_UNKNOWN_13: | |||||
| case OPCODE_UNKNOWN_14: | |||||
| case OPCODE_UNKNOWN_15: | |||||
| debug_ipmovie("unknown (but documented) opcode %02X\n", opcode_type); | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_SEND_BUFFER: | |||||
| debug_ipmovie("send buffer\n"); | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_AUDIO_FRAME: | |||||
| debug_ipmovie("audio frame\n"); | |||||
| /* log position and move on for now */ | |||||
| s->audio_chunk_offset = url_ftell(pb); | |||||
| s->audio_chunk_size = opcode_size; | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_SILENCE_FRAME: | |||||
| debug_ipmovie("silence frame\n"); | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_INIT_VIDEO_MODE: | |||||
| debug_ipmovie("initialize video mode\n"); | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_CREATE_GRADIENT: | |||||
| debug_ipmovie("create gradient\n"); | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_SET_PALETTE: | |||||
| debug_ipmovie("set palette\n"); | |||||
| /* check for the logical maximum palette size | |||||
| * (3 * 256 + 4 bytes) */ | |||||
| if (opcode_size > 0x304) { | |||||
| debug_ipmovie("demux_ipmovie: set_palette opcode too large\n"); | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| if (get_buffer(pb, scratch, opcode_size) != opcode_size) { | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| /* load the palette into internal data structure */ | |||||
| first_color = LE_16(&scratch[0]); | |||||
| last_color = LE_16(&scratch[2]); | |||||
| /* sanity check (since they are 16 bit values) */ | |||||
| if ((first_color > 0xFF) || (last_color > 0xFF)) { | |||||
| debug_ipmovie("demux_ipmovie: set_palette indices out of range (%d -> %d)\n", | |||||
| first_color, last_color); | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| j = 4; /* offset of first palette data */ | |||||
| #if 0 | |||||
| for (i = first_color; i <= last_color; i++) { | |||||
| s->palette[i].r = scratch[j++] * 4; | |||||
| s->palette[i].g = scratch[j++] * 4; | |||||
| s->palette[i].b = scratch[j++] * 4; | |||||
| } | |||||
| #endif | |||||
| break; | |||||
| case OPCODE_SET_PALETTE_COMPRESSED: | |||||
| debug_ipmovie("set palette compressed\n"); | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_SET_DECODING_MAP: | |||||
| debug_ipmovie("set decoding map\n"); | |||||
| /* log position and move on for now */ | |||||
| s->decode_map_chunk_offset = url_ftell(pb); | |||||
| s->decode_map_chunk_size = opcode_size; | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| case OPCODE_VIDEO_DATA: | |||||
| debug_ipmovie("set video data\n"); | |||||
| /* log position and move on for now */ | |||||
| s->video_chunk_offset = url_ftell(pb); | |||||
| s->video_chunk_size = opcode_size; | |||||
| url_fseek(pb, opcode_size, SEEK_CUR); | |||||
| break; | |||||
| default: | |||||
| debug_ipmovie("*** unknown opcode type\n"); | |||||
| chunk_type = CHUNK_BAD; | |||||
| break; | |||||
| } | |||||
| } | |||||
| /* make a note of where the stream is sitting */ | |||||
| s->next_chunk_offset = url_ftell(pb); | |||||
| /* dispatch the first of any pending packets */ | |||||
| if ((chunk_type == CHUNK_VIDEO) || (chunk_type == CHUNK_AUDIO_ONLY)) | |||||
| chunk_type = load_ipmovie_packet(s, pb, pkt); | |||||
| return chunk_type; | |||||
| } | |||||
| static int ipmovie_probe(AVProbeData *p) | |||||
| { | |||||
| if (p->buf_size < IPMOVIE_SIGNATURE_SIZE) | |||||
| return 0; | |||||
| if (strncmp(p->buf, IPMOVIE_SIGNATURE, IPMOVIE_SIGNATURE_SIZE) != 0) | |||||
| return 0; | |||||
| return AVPROBE_SCORE_MAX; | |||||
| } | |||||
| static int ipmovie_read_header(AVFormatContext *s, | |||||
| AVFormatParameters *ap) | |||||
| { | |||||
| IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data; | |||||
| ByteIOContext *pb = &s->pb; | |||||
| AVPacket pkt; | |||||
| AVStream *st; | |||||
| /* initialize private context members */ | |||||
| ipmovie->video_pts = ipmovie->audio_frame_count = 0; | |||||
| ipmovie->audio_chunk_offset = ipmovie->video_chunk_offset = | |||||
| ipmovie->decode_map_chunk_offset = 0; | |||||
| /* on the first read, this will position the stream at the first chunk */ | |||||
| ipmovie->next_chunk_offset = IPMOVIE_SIGNATURE_SIZE + 6; | |||||
| /* process the first chunk which should be CHUNK_INIT_VIDEO */ | |||||
| if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO) | |||||
| return AVERROR_INVALIDDATA; | |||||
| /* process the next chunk which should be CHUNK_INIT_AUDIO */ | |||||
| if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_AUDIO) | |||||
| return AVERROR_INVALIDDATA; | |||||
| /* set the pts reference (1 pts = 1/90000) */ | |||||
| s->pts_num = 1; | |||||
| s->pts_den = 90000; | |||||
| /* initialize the stream decoders */ | |||||
| st = av_new_stream(s, 0); | |||||
| if (!st) | |||||
| return AVERROR_NOMEM; | |||||
| ipmovie->video_stream_index = st->index; | |||||
| st->codec.codec_type = CODEC_TYPE_VIDEO; | |||||
| st->codec.codec_id = CODEC_ID_INTERPLAY_VIDEO; | |||||
| st->codec.codec_tag = 0; /* no fourcc */ | |||||
| st->codec.width = ipmovie->video_width; | |||||
| st->codec.height = ipmovie->video_height; | |||||
| st = av_new_stream(s, 0); | |||||
| if (!st) | |||||
| return AVERROR_NOMEM; | |||||
| ipmovie->audio_stream_index = st->index; | |||||
| st->codec.codec_type = CODEC_TYPE_AUDIO; | |||||
| st->codec.codec_id = ipmovie->audio_type; | |||||
| st->codec.codec_tag = 0; /* no tag */ | |||||
| st->codec.channels = ipmovie->audio_channels; | |||||
| st->codec.sample_rate = ipmovie->audio_sample_rate; | |||||
| st->codec.bits_per_sample = ipmovie->audio_bits; | |||||
| st->codec.bit_rate = st->codec.channels * st->codec.sample_rate * | |||||
| st->codec.bits_per_sample / | |||||
| (st->codec.codec_id == CODEC_ID_INTERPLAY_DPCM) ? 2 : 1; | |||||
| st->codec.block_align = st->codec.channels * st->codec.bits_per_sample; | |||||
| return 0; | |||||
| } | |||||
| static int ipmovie_read_packet(AVFormatContext *s, | |||||
| AVPacket *pkt) | |||||
| { | |||||
| IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data; | |||||
| ByteIOContext *pb = &s->pb; | |||||
| int ret; | |||||
| ret = process_ipmovie_chunk(ipmovie, pb, pkt); | |||||
| if (ret == CHUNK_BAD) | |||||
| ret = AVERROR_INVALIDDATA; | |||||
| else if (ret == CHUNK_EOF) | |||||
| ret = -EIO; | |||||
| else if (ret == CHUNK_NOMEM) | |||||
| ret = AVERROR_NOMEM; | |||||
| else | |||||
| ret = 0; | |||||
| return ret; | |||||
| } | |||||
| static int ipmovie_read_close(AVFormatContext *s) | |||||
| { | |||||
| // IPMVEContext *ipmovie = (IPMVEContext *)s->priv_data; | |||||
| return 0; | |||||
| } | |||||
| static AVInputFormat ipmovie_iformat = { | |||||
| "ipmovie", | |||||
| "Interplay MVE format", | |||||
| sizeof(IPMVEContext), | |||||
| ipmovie_probe, | |||||
| ipmovie_read_header, | |||||
| ipmovie_read_packet, | |||||
| ipmovie_read_close, | |||||
| }; | |||||
| int ipmovie_init(void) | |||||
| { | |||||
| av_register_input_format(&ipmovie_iformat); | |||||
| return 0; | |||||
| } | |||||