2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "vd_internal.h"
28 //#undef MPEG12_POSTPROC
30 static const vd_info_t info
=
32 "libmpeg2 MPEG 1/2 Video decoder",
34 "A'rpi & Fabian Franz",
39 LIBVD_EXTERN(libmpeg2
)
41 //#include "libvo/video_out.h" // FIXME!!!
43 #include "libmpeg2/mpeg2.h"
44 #include "libmpeg2/attributes.h"
45 #include "libmpeg2/mpeg2_internal.h"
47 #include "cpudetect.h"
59 // to set/get/query special features/parameters
60 static int control(sh_video_t
*sh
,int cmd
,void* arg
,...){
61 vd_libmpeg2_ctx_t
*context
= sh
->context
;
62 mpeg2dec_t
* mpeg2dec
= context
->mpeg2dec
;
63 const mpeg2_info_t
* info
= mpeg2_info (mpeg2dec
);
66 case VDCTRL_QUERY_FORMAT
:
67 if (info
->sequence
->width
>> 1 == info
->sequence
->chroma_width
&&
68 info
->sequence
->height
>> 1 == info
->sequence
->chroma_height
&&
69 (*((int*)arg
)) == IMGFMT_YV12
)
71 if (info
->sequence
->width
>> 1 == info
->sequence
->chroma_width
&&
72 info
->sequence
->height
== info
->sequence
->chroma_height
&&
73 (*((int*)arg
)) == IMGFMT_422P
)
78 return CONTROL_UNKNOWN
;
82 static int init(sh_video_t
*sh
){
83 vd_libmpeg2_ctx_t
*context
;
84 mpeg2dec_t
* mpeg2dec
;
85 // const mpeg2_info_t * info;
90 accel
|= MPEG2_ACCEL_X86_MMX
;
92 accel
|= MPEG2_ACCEL_X86_MMXEXT
;
94 accel
|= MPEG2_ACCEL_X86_3DNOW
;
96 accel
|= MPEG2_ACCEL_X86_SSE2
;
97 if(gCpuCaps
.hasAltiVec
)
98 accel
|= MPEG2_ACCEL_PPC_ALTIVEC
;
100 accel
|= MPEG2_ACCEL_ALPHA
;
102 accel
|= MPEG2_ACCEL_ARM
;
105 accel
|= MPEG2_ACCEL_ALPHA_MVI
;
107 accel
|= MPEG2_ACCEL_SPARC_VIS
;
111 mpeg2dec
= mpeg2_init ();
113 if(!mpeg2dec
) return 0;
115 mpeg2_custom_fbuf(mpeg2dec
,1); // enable DR1
117 context
= calloc(1, sizeof(vd_libmpeg2_ctx_t
));
118 context
->mpeg2dec
= mpeg2dec
;
119 sh
->context
= context
;
121 mpeg2dec
->pending_buffer
= 0;
122 mpeg2dec
->pending_length
= 0;
128 static void uninit(sh_video_t
*sh
){
130 vd_libmpeg2_ctx_t
*context
= sh
->context
;
131 mpeg2dec_t
* mpeg2dec
= context
->mpeg2dec
;
132 free(mpeg2dec
->pending_buffer
);
133 mpeg2dec
->decoder
.convert
=NULL
;
134 mpeg2dec
->decoder
.convert_id
=NULL
;
135 mpeg2_close (mpeg2dec
);
136 for (i
=0; i
< 3; i
++)
137 free(context
->quant_store
[i
]);
141 static void draw_slice (void * _sh
, uint8_t * const * src
, unsigned int y
){
142 sh_video_t
* sh
= (sh_video_t
*) _sh
;
143 vd_libmpeg2_ctx_t
*context
= sh
->context
;
144 mpeg2dec_t
* mpeg2dec
= context
->mpeg2dec
;
145 const mpeg2_info_t
* info
= mpeg2_info (mpeg2dec
);
146 int stride
[MP_MAX_PLANES
] = {mpeg2dec
->decoder
.stride
, mpeg2dec
->decoder
.uv_stride
, mpeg2dec
->decoder
.uv_stride
};
147 uint8_t *srcs
[MP_MAX_PLANES
] = {src
[0], src
[1], src
[2]};
149 // printf("draw_slice() y=%d \n",y);
151 mpcodecs_draw_slice(sh
, srcs
,
152 stride
, info
->sequence
->picture_width
,
153 (y
+16<=info
->sequence
->picture_height
) ? 16 :
154 info
->sequence
->picture_height
-y
,
159 static mp_image_t
* decode(sh_video_t
*sh
,void* data
,int len
,int flags
){
160 vd_libmpeg2_ctx_t
*context
= sh
->context
;
161 mpeg2dec_t
* mpeg2dec
= context
->mpeg2dec
;
162 const mpeg2_info_t
* info
= mpeg2_info (mpeg2dec
);
163 int drop_frame
, framedrop
=flags
&3;
165 // MPlayer registers its own draw_slice callback, prevent libmpeg2 from freeing the context
166 mpeg2dec
->decoder
.convert
=NULL
;
167 mpeg2dec
->decoder
.convert_id
=NULL
;
169 if(len
<=0) return NULL
; // skipped null frame
171 // append extra 'end of frame' code:
172 ((char*)data
+len
)[0]=0;
173 ((char*)data
+len
)[1]=0;
174 ((char*)data
+len
)[2]=1;
175 ((char*)data
+len
)[3]=0xff;
178 if (mpeg2dec
->pending_length
) {
179 mpeg2_buffer (mpeg2dec
, mpeg2dec
->pending_buffer
, mpeg2dec
->pending_buffer
+ mpeg2dec
->pending_length
);
181 mpeg2_buffer (mpeg2dec
, data
, (uint8_t *)data
+len
);
185 int state
=mpeg2_parse (mpeg2dec
);
186 int type
, use_callback
;
188 unsigned long pw
, ph
;
193 if (mpeg2dec
->pending_length
) {
194 // just finished the pending data, continue with processing of the passed buffer
195 mpeg2dec
->pending_length
= 0;
196 mpeg2_buffer (mpeg2dec
, data
, (uint8_t *)data
+len
);
198 // parsing of the passed buffer finished, return.
203 pw
= info
->sequence
->display_width
* info
->sequence
->pixel_width
;
204 ph
= info
->sequence
->display_height
* info
->sequence
->pixel_height
;
205 if(ph
) sh
->aspect
= (float) pw
/ (float) ph
;
206 // video parameters initialized/changed, (re)init libvo:
207 if (info
->sequence
->width
>> 1 == info
->sequence
->chroma_width
&&
208 info
->sequence
->height
>> 1 == info
->sequence
->chroma_height
) {
209 imgfmt
= IMGFMT_YV12
;
210 } else if (info
->sequence
->width
>> 1 == info
->sequence
->chroma_width
&&
211 info
->sequence
->height
== info
->sequence
->chroma_height
) {
212 imgfmt
= IMGFMT_422P
;
214 if (imgfmt
== context
->imgfmt
&&
215 info
->sequence
->picture_width
== context
->width
&&
216 info
->sequence
->picture_height
== context
->height
&&
217 sh
->aspect
== context
->aspect
)
219 if(!mpcodecs_config_vo(sh
,
220 info
->sequence
->picture_width
,
221 info
->sequence
->picture_height
, imgfmt
))
223 context
->imgfmt
= imgfmt
;
224 context
->width
= info
->sequence
->picture_width
;
225 context
->height
= info
->sequence
->picture_height
;
226 context
->aspect
= sh
->aspect
;
229 type
=info
->current_picture
->flags
&PIC_MASK_CODING_TYPE
;
231 drop_frame
= framedrop
&& (mpeg2dec
->decoder
.coding_type
== B_TYPE
);
232 drop_frame
|= framedrop
>=2; // hard drop
234 mpeg2_skip(mpeg2dec
, 1);
235 //printf("Dropping Frame ...\n");
238 mpeg2_skip(mpeg2dec
, 0); //mpeg2skip skips frames until set again to 0
240 use_callback
= (!framedrop
&& sh
->opts
->vd_use_slices
&&
241 (info
->current_picture
->flags
&PIC_FLAG_PROGRESSIVE_FRAME
)) ?
242 MP_IMGFLAG_DRAW_CALLBACK
:0;
244 // get_buffer "callback":
245 mpi_new
=mpcodecs_get_image(sh
,MP_IMGTYPE_IPB
,
246 (type
==PIC_FLAG_CODING_TYPE_B
) ?
247 use_callback
: (MP_IMGFLAG_PRESERVE
|MP_IMGFLAG_READABLE
),
248 info
->sequence
->width
,
249 info
->sequence
->height
);
251 if(!mpi_new
) return 0; // VO ERROR!!!!!!!!
252 mpeg2_set_buf(mpeg2dec
, mpi_new
->planes
, mpi_new
);
253 mpi_new
->stride
[0] = info
->sequence
->width
;
254 mpi_new
->stride
[1] = info
->sequence
->chroma_width
;
255 mpi_new
->stride
[2] = info
->sequence
->chroma_width
;
256 if (info
->current_picture
->flags
&PIC_FLAG_TOP_FIELD_FIRST
)
257 mpi_new
->fields
|= MP_IMGFIELD_TOP_FIRST
;
258 else mpi_new
->fields
&= ~MP_IMGFIELD_TOP_FIRST
;
259 if (info
->current_picture
->flags
&PIC_FLAG_REPEAT_FIRST_FIELD
)
260 mpi_new
->fields
|= MP_IMGFIELD_REPEAT_FIRST
;
261 else mpi_new
->fields
&= ~MP_IMGFIELD_REPEAT_FIRST
;
262 mpi_new
->fields
|= MP_IMGFIELD_ORDERED
;
263 if (!(info
->current_picture
->flags
&PIC_FLAG_PROGRESSIVE_FRAME
))
264 mpi_new
->fields
|= MP_IMGFIELD_INTERLACED
;
266 #ifdef MPEG12_POSTPROC
267 mpi_new
->qstride
=info
->sequence
->width
>>4;
269 char **p
= &context
->quant_store
[type
==PIC_FLAG_CODING_TYPE_B
?
270 2 : (context
->quant_store_idx
^= 1)];
271 *p
= realloc(*p
, mpi_new
->qstride
*(info
->sequence
->height
>>4));
272 mpi_new
->qscale
= *p
;
274 mpeg2dec
->decoder
.quant_store
=mpi_new
->qscale
;
275 mpeg2dec
->decoder
.quant_stride
=mpi_new
->qstride
;
276 mpi_new
->pict_type
=type
; // 1->I, 2->P, 3->B
277 mpi_new
->qscale_type
= 1;
280 if (mpi_new
->flags
&MP_IMGFLAG_DRAW_CALLBACK
281 && !(mpi_new
->flags
&MP_IMGFLAG_DIRECT
)) {
282 // nice, filter/vo likes draw_callback :)
283 mpeg2dec
->decoder
.convert
=draw_slice
;
284 mpeg2dec
->decoder
.convert_id
=sh
;
286 mpeg2dec
->decoder
.convert
=NULL
;
287 mpeg2dec
->decoder
.convert_id
=NULL
;
293 case STATE_INVALID_END
:
295 if(info
->display_fbuf
) {
296 mp_image_t
* mpi
= info
->display_fbuf
->id
;
297 if (mpeg2dec
->pending_length
== 0) {
298 mpeg2dec
->pending_length
= mpeg2dec
->buf_end
- mpeg2dec
->buf_start
;
299 mpeg2dec
->pending_buffer
= realloc(mpeg2dec
->pending_buffer
, mpeg2dec
->pending_length
);
300 memcpy(mpeg2dec
->pending_buffer
, mpeg2dec
->buf_start
, mpeg2dec
->pending_length
);
302 // still some data in the pending buffer, shouldn't happen
303 mpeg2dec
->pending_length
= mpeg2dec
->buf_end
- mpeg2dec
->buf_start
;
304 memmove(mpeg2dec
->pending_buffer
, mpeg2dec
->buf_start
, mpeg2dec
->pending_length
);
305 mpeg2dec
->pending_buffer
= realloc(mpeg2dec
->pending_buffer
, mpeg2dec
->pending_length
+ len
);
306 memcpy(mpeg2dec
->pending_buffer
+mpeg2dec
->pending_length
, data
, len
);
307 mpeg2dec
->pending_length
+= len
;
309 // fprintf(stderr, "pending = %d\n", mpeg2dec->pending_length);