Mercurial > libavcodec.hg
annotate eacmv.c @ 11557:53822d92c3f7 libavcodec
Make sure the EC code does not attempt to use inter based concealment if there
is no reference frame available. (this can happen because the EC code will attempt
to use reference frames even for I/IDR frames)
author | michael |
---|---|
date | Tue, 30 Mar 2010 20:46:46 +0000 |
parents | dff431441c9c |
children | 8a4984c5cacc |
rev | line source |
---|---|
7222 | 1 /* |
2 * Electronic Arts CMV Video Decoder | |
3 * Copyright (c) 2007-2008 Peter Ross | |
4 * | |
5 * This file is part of FFmpeg. | |
6 * | |
7 * FFmpeg is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Lesser General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2.1 of the License, or (at your option) any later version. | |
11 * | |
12 * FFmpeg is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Lesser General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Lesser General Public | |
18 * License along with FFmpeg; if not, write to the Free Software | |
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
20 */ | |
21 | |
22 /** | |
8718
e9d9d946f213
Use full internal pathname in doxygen @file directives.
diego
parents:
8573
diff
changeset
|
23 * @file libavcodec/eacmv.c |
7222 | 24 * Electronic Arts CMV Video Decoder |
10825 | 25 * by Peter Ross (pross@xvid.org) |
7222 | 26 * |
27 * Technical details here: | |
28 * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_CMV | |
29 */ | |
30 | |
8573
2acf0ae7b041
Fix build: Add intreadwrite.h and bswap.h #includes where necessary.
diego
parents:
7222
diff
changeset
|
31 #include "libavutil/intreadwrite.h" |
7222 | 32 #include "avcodec.h" |
33 | |
34 typedef struct CmvContext { | |
35 AVCodecContext *avctx; | |
36 AVFrame frame; ///< current | |
37 AVFrame last_frame; ///< last | |
38 AVFrame last2_frame; ///< second-last | |
39 int width, height; | |
40 unsigned int palette[AVPALETTE_COUNT]; | |
41 } CmvContext; | |
42 | |
43 static av_cold int cmv_decode_init(AVCodecContext *avctx){ | |
44 CmvContext *s = avctx->priv_data; | |
45 s->avctx = avctx; | |
46 avctx->pix_fmt = PIX_FMT_PAL8; | |
47 return 0; | |
48 } | |
49 | |
50 static void cmv_decode_intra(CmvContext * s, const uint8_t *buf, const uint8_t *buf_end){ | |
51 unsigned char *dst = s->frame.data[0]; | |
52 int i; | |
53 | |
54 for (i=0; i < s->avctx->height && buf+s->avctx->width<=buf_end; i++) { | |
55 memcpy(dst, buf, s->avctx->width); | |
56 dst += s->frame.linesize[0]; | |
57 buf += s->avctx->width; | |
58 } | |
59 } | |
60 | |
61 static void cmv_motcomp(unsigned char *dst, int dst_stride, | |
62 const unsigned char *src, int src_stride, | |
63 int x, int y, | |
64 int xoffset, int yoffset, | |
65 int width, int height){ | |
66 int i,j; | |
67 | |
68 for(j=y;j<y+4;j++) | |
69 for(i=x;i<x+4;i++) | |
70 { | |
71 if (i+xoffset>=0 && i+xoffset<width && | |
72 j+yoffset>=0 && j+yoffset<height) { | |
73 dst[j*dst_stride + i] = src[(j+yoffset)*src_stride + i+xoffset]; | |
74 }else{ | |
75 dst[j*dst_stride + i] = 0; | |
76 } | |
77 } | |
78 } | |
79 | |
80 static void cmv_decode_inter(CmvContext * s, const uint8_t *buf, const uint8_t *buf_end){ | |
81 const uint8_t *raw = buf + (s->avctx->width*s->avctx->height/16); | |
82 int x,y,i; | |
83 | |
84 i = 0; | |
85 for(y=0; y<s->avctx->height/4; y++) | |
86 for(x=0; x<s->avctx->width/4 && buf+i<buf_end; x++) { | |
87 if (buf[i]==0xFF) { | |
88 unsigned char *dst = s->frame.data[0] + (y*4)*s->frame.linesize[0] + x*4; | |
89 if (raw+16<buf_end && *raw==0xFF) { /* intra */ | |
90 raw++; | |
91 memcpy(dst, raw, 4); | |
92 memcpy(dst+s->frame.linesize[0], raw+4, 4); | |
93 memcpy(dst+2*s->frame.linesize[0], raw+8, 4); | |
94 memcpy(dst+3*s->frame.linesize[0], raw+12, 4); | |
95 raw+=16; | |
96 }else if(raw<buf_end) { /* inter using second-last frame as reference */ | |
97 int xoffset = (*raw & 0xF) - 7; | |
98 int yoffset = ((*raw >> 4)) - 7; | |
99 cmv_motcomp(s->frame.data[0], s->frame.linesize[0], | |
100 s->last2_frame.data[0], s->last2_frame.linesize[0], | |
101 x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height); | |
102 raw++; | |
103 } | |
104 }else{ /* inter using last frame as reference */ | |
105 int xoffset = (buf[i] & 0xF) - 7; | |
106 int yoffset = ((buf[i] >> 4)) - 7; | |
107 cmv_motcomp(s->frame.data[0], s->frame.linesize[0], | |
108 s->last_frame.data[0], s->last_frame.linesize[0], | |
109 x*4, y*4, xoffset, yoffset, s->avctx->width, s->avctx->height); | |
110 } | |
111 i++; | |
112 } | |
113 } | |
114 | |
115 static void cmv_process_header(CmvContext *s, const uint8_t *buf, const uint8_t *buf_end) | |
116 { | |
117 int pal_start, pal_count, i; | |
118 | |
119 if(buf+16>=buf_end) { | |
120 av_log(s->avctx, AV_LOG_WARNING, "truncated header\n"); | |
121 return; | |
122 } | |
123 | |
124 s->width = AV_RL16(&buf[4]); | |
125 s->height = AV_RL16(&buf[6]); | |
126 if (s->avctx->width!=s->width || s->avctx->height!=s->height) | |
127 avcodec_set_dimensions(s->avctx, s->width, s->height); | |
128 | |
129 s->avctx->time_base.num = 1; | |
130 s->avctx->time_base.den = AV_RL16(&buf[10]); | |
131 | |
132 pal_start = AV_RL16(&buf[12]); | |
133 pal_count = AV_RL16(&buf[14]); | |
134 | |
135 buf += 16; | |
136 for (i=pal_start; i<pal_start+pal_count && i<AVPALETTE_COUNT && buf+2<buf_end; i++) { | |
137 s->palette[i] = AV_RB24(buf); | |
138 buf += 3; | |
139 } | |
140 } | |
141 | |
142 #define EA_PREAMBLE_SIZE 8 | |
143 #define MVIh_TAG MKTAG('M', 'V', 'I', 'h') | |
144 | |
145 static int cmv_decode_frame(AVCodecContext *avctx, | |
146 void *data, int *data_size, | |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
147 AVPacket *avpkt) |
7222 | 148 { |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
149 const uint8_t *buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
9083
diff
changeset
|
150 int buf_size = avpkt->size; |
7222 | 151 CmvContext *s = avctx->priv_data; |
152 const uint8_t *buf_end = buf + buf_size; | |
153 | |
154 if (AV_RL32(buf)==MVIh_TAG||AV_RB32(buf)==MVIh_TAG) { | |
155 cmv_process_header(s, buf+EA_PREAMBLE_SIZE, buf_end); | |
156 return buf_size; | |
157 } | |
158 | |
159 if (avcodec_check_dimensions(s->avctx, s->width, s->height)) | |
160 return -1; | |
161 | |
162 /* shuffle */ | |
163 if (s->last2_frame.data[0]) | |
164 avctx->release_buffer(avctx, &s->last2_frame); | |
165 FFSWAP(AVFrame, s->last_frame, s->last2_frame); | |
166 FFSWAP(AVFrame, s->frame, s->last_frame); | |
167 | |
168 s->frame.reference = 1; | |
169 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; | |
170 if (avctx->get_buffer(avctx, &s->frame)<0) { | |
171 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
172 return -1; | |
173 } | |
174 | |
175 memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); | |
176 | |
177 buf += EA_PREAMBLE_SIZE; | |
178 if ((buf[0]&1)) { // subtype | |
179 cmv_decode_inter(s, buf+2, buf_end); | |
180 s->frame.key_frame = 0; | |
181 s->frame.pict_type = FF_P_TYPE; | |
182 }else{ | |
183 s->frame.key_frame = 1; | |
184 s->frame.pict_type = FF_I_TYPE; | |
185 cmv_decode_intra(s, buf+2, buf_end); | |
186 } | |
187 | |
188 *data_size = sizeof(AVFrame); | |
189 *(AVFrame*)data = s->frame; | |
190 | |
191 return buf_size; | |
192 } | |
193 | |
194 static av_cold int cmv_decode_end(AVCodecContext *avctx){ | |
195 CmvContext *s = avctx->priv_data; | |
196 if (s->frame.data[0]) | |
197 s->avctx->release_buffer(avctx, &s->frame); | |
198 if (s->last_frame.data[0]) | |
199 s->avctx->release_buffer(avctx, &s->last_frame); | |
200 if (s->last2_frame.data[0]) | |
201 s->avctx->release_buffer(avctx, &s->last2_frame); | |
202 | |
203 return 0; | |
204 } | |
205 | |
206 AVCodec eacmv_decoder = { | |
207 "eacmv", | |
208 CODEC_TYPE_VIDEO, | |
209 CODEC_ID_CMV, | |
210 sizeof(CmvContext), | |
211 cmv_decode_init, | |
212 NULL, | |
213 cmv_decode_end, | |
214 cmv_decode_frame, | |
215 CODEC_CAP_DR1, | |
9083
bf274494b66e
Change a bunch of codec long_names to be more consistent and descriptive.
diego
parents:
8718
diff
changeset
|
216 .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts CMV video"), |
7222 | 217 }; |