savage_vid added
[mplayer/greg.git] / libmpcodecs / vd_libmpeg2.c
blob2b367e0544bf6d29f77c3081692d25f2ec5a480b
1 #include <stdio.h>
2 #include <stdlib.h>
4 #include "config.h"
5 #ifdef USE_LIBMPEG2
7 #include "mp_msg.h"
9 #include "vd_internal.h"
11 //#undef MPEG12_POSTPROC
13 static vd_info_t info =
15 "MPEG 1/2 Video decoder libmpeg2-v0.4.0b",
16 "libmpeg2",
17 "A'rpi & Fabian Franz",
18 "Aaron & Walken",
19 "native"
22 LIBVD_EXTERN(libmpeg2)
24 //#include "libvo/video_out.h" // FIXME!!!
26 #include "libmpeg2/mpeg2.h"
27 #include "libmpeg2/attributes.h"
28 #include "libmpeg2/mpeg2_internal.h"
30 #include "../cpudetect.h"
32 // to set/get/query special features/parameters
33 static int control(sh_video_t *sh,int cmd,void* arg,...){
34 mpeg2dec_t * mpeg2dec = sh->context;
35 const mpeg2_info_t * info = mpeg2_info (mpeg2dec);
37 switch(cmd) {
38 case VDCTRL_QUERY_FORMAT:
39 if (info->sequence->width >> 1 == info->sequence->chroma_width &&
40 info->sequence->height >> 1 == info->sequence->chroma_height &&
41 (*((int*)arg)) == IMGFMT_YV12)
42 return CONTROL_TRUE;
43 if (info->sequence->width >> 1 == info->sequence->chroma_width &&
44 info->sequence->height == info->sequence->chroma_height &&
45 (*((int*)arg)) == IMGFMT_422P)
46 return CONTROL_TRUE;
47 return CONTROL_FALSE;
50 return CONTROL_UNKNOWN;
53 // init driver
54 static int init(sh_video_t *sh){
55 mpeg2dec_t * mpeg2dec;
56 // const mpeg2_info_t * info;
57 int accel;
59 accel = 0;
60 if(gCpuCaps.hasMMX)
61 accel |= MPEG2_ACCEL_X86_MMX;
62 if(gCpuCaps.hasMMX2)
63 accel |= MPEG2_ACCEL_X86_MMXEXT;
64 if(gCpuCaps.has3DNow)
65 accel |= MPEG2_ACCEL_X86_3DNOW;
66 if(gCpuCaps.hasAltiVec)
67 accel |= MPEG2_ACCEL_PPC_ALTIVEC;
68 #ifdef HAVE_VIS
69 accel |= MPEG2_ACCEL_SPARC_VIS;
70 #endif
71 mpeg2_accel(accel);
73 mpeg2dec = mpeg2_init ();
75 if(!mpeg2dec) return 0;
77 mpeg2_custom_fbuf(mpeg2dec,1); // enable DR1
79 sh->context=mpeg2dec;
81 mpeg2dec->pending_buffer = 0;
82 mpeg2dec->pending_length = 0;
84 return 1;
87 // uninit driver
88 static void uninit(sh_video_t *sh){
89 mpeg2dec_t * mpeg2dec = sh->context;
90 if (mpeg2dec->pending_buffer) free(mpeg2dec->pending_buffer);
91 mpeg2dec->decoder.convert=NULL;
92 mpeg2dec->decoder.convert_id=NULL;
93 mpeg2_close (mpeg2dec);
96 static void draw_slice (void * _sh, uint8_t * const * src, unsigned int y){
97 sh_video_t* sh = (sh_video_t*) _sh;
98 mpeg2dec_t* mpeg2dec = sh->context;
99 const mpeg2_info_t * info = mpeg2_info (mpeg2dec);
100 int stride[3];
102 // printf("draw_slice() y=%d \n",y);
104 stride[0]=mpeg2dec->decoder.stride;
105 stride[1]=stride[2]=mpeg2dec->decoder.uv_stride;
107 mpcodecs_draw_slice(sh, (uint8_t **)src,
108 stride, info->sequence->picture_width,
109 (y+16<=info->sequence->picture_height) ? 16 :
110 info->sequence->picture_height-y,
111 0, y);
114 // decode a frame
115 static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
116 mpeg2dec_t * mpeg2dec = sh->context;
117 const mpeg2_info_t * info = mpeg2_info (mpeg2dec);
118 int drop_frame, framedrop=flags&3;
120 // MPlayer registers its own draw_slice callback, prevent libmpeg2 from freeing the context
121 mpeg2dec->decoder.convert=NULL;
122 mpeg2dec->decoder.convert_id=NULL;
124 if(len<=0) return NULL; // skipped null frame
126 // append extra 'end of frame' code:
127 ((char*)data+len)[0]=0;
128 ((char*)data+len)[1]=0;
129 ((char*)data+len)[2]=1;
130 ((char*)data+len)[3]=0xff;
131 len+=4;
133 if (mpeg2dec->pending_length) {
134 mpeg2_buffer (mpeg2dec, mpeg2dec->pending_buffer, mpeg2dec->pending_buffer + mpeg2dec->pending_length);
135 } else {
136 mpeg2_buffer (mpeg2dec, data, data+len);
139 while(1){
140 int state=mpeg2_parse (mpeg2dec);
141 int type, use_callback;
142 mp_image_t* mpi_new;
144 switch(state){
145 case STATE_BUFFER:
146 if (mpeg2dec->pending_length) {
147 // just finished the pending data, continue with processing of the passed buffer
148 mpeg2dec->pending_length = 0;
149 mpeg2_buffer (mpeg2dec, data, data+len);
150 } else {
151 // parsing of the passed buffer finished, return.
152 return 0;
154 break;
155 case STATE_SEQUENCE:
156 // video parameters inited/changed, (re)init libvo:
157 if (info->sequence->width >> 1 == info->sequence->chroma_width &&
158 info->sequence->height >> 1 == info->sequence->chroma_height) {
159 if(!mpcodecs_config_vo(sh,
160 info->sequence->picture_width,
161 info->sequence->picture_height, IMGFMT_YV12)) return 0;
162 } else if (info->sequence->width >> 1 == info->sequence->chroma_width &&
163 info->sequence->height == info->sequence->chroma_height) {
164 if(!mpcodecs_config_vo(sh,
165 info->sequence->picture_width,
166 info->sequence->picture_height, IMGFMT_422P)) return 0;
167 } else return 0;
168 break;
169 case STATE_PICTURE:
170 type=info->current_picture->flags&PIC_MASK_CODING_TYPE;
172 drop_frame = framedrop && (mpeg2dec->decoder.coding_type == B_TYPE);
173 drop_frame |= framedrop>=2; // hard drop
174 if (drop_frame) {
175 mpeg2_skip(mpeg2dec, 1);
176 //printf("Dropping Frame ...\n");
177 break;
179 mpeg2_skip(mpeg2dec, 0); //mpeg2skip skips frames until set again to 0
181 use_callback = (!framedrop && vd_use_slices &&
182 (info->current_picture->flags&PIC_FLAG_PROGRESSIVE_FRAME)) ?
183 MP_IMGFLAG_DRAW_CALLBACK:0;
185 // get_buffer "callback":
186 mpi_new=mpcodecs_get_image(sh,MP_IMGTYPE_IPB,
187 (type==PIC_FLAG_CODING_TYPE_B) ?
188 use_callback : (MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE),
189 info->sequence->width,
190 info->sequence->height);
192 if(!mpi_new) return 0; // VO ERROR!!!!!!!!
193 mpeg2_set_buf(mpeg2dec, mpi_new->planes, mpi_new);
194 if (info->current_picture->flags&PIC_FLAG_TOP_FIELD_FIRST)
195 mpi_new->fields |= MP_IMGFIELD_TOP_FIRST;
196 else mpi_new->fields &= ~MP_IMGFIELD_TOP_FIRST;
197 if (info->current_picture->flags&PIC_FLAG_REPEAT_FIRST_FIELD)
198 mpi_new->fields |= MP_IMGFIELD_REPEAT_FIRST;
199 else mpi_new->fields &= ~MP_IMGFIELD_REPEAT_FIRST;
200 mpi_new->fields |= MP_IMGFIELD_ORDERED;
202 #ifdef MPEG12_POSTPROC
203 if(!mpi_new->qscale){
204 mpi_new->qstride=info->sequence->width>>4;
205 mpi_new->qscale=malloc(mpi_new->qstride*(info->sequence->height>>4));
207 mpeg2dec->decoder.quant_store=mpi_new->qscale;
208 mpeg2dec->decoder.quant_stride=mpi_new->qstride;
209 mpi_new->pict_type=type; // 1->I, 2->P, 3->B
210 mpi_new->qscale_type= 1;
211 #endif
213 if (mpi_new->flags&MP_IMGFLAG_DRAW_CALLBACK
214 && !(mpi_new->flags&MP_IMGFLAG_DIRECT)) {
215 // nice, filter/vo likes draw_callback :)
216 mpeg2dec->decoder.convert=draw_slice;
217 mpeg2dec->decoder.convert_id=sh;
218 } else {
219 mpeg2dec->decoder.convert=NULL;
220 mpeg2dec->decoder.convert_id=NULL;
223 break;
224 case STATE_SLICE:
225 case STATE_END:
226 case STATE_INVALID_END:
227 // decoding done:
228 if(info->display_fbuf) {
229 mp_image_t* mpi = info->display_fbuf->id;
230 if (mpeg2dec->pending_length == 0) {
231 mpeg2dec->pending_length = mpeg2dec->buf_end - mpeg2dec->buf_start;
232 mpeg2dec->pending_buffer = realloc(mpeg2dec->pending_buffer, mpeg2dec->pending_length);
233 memcpy(mpeg2dec->pending_buffer, mpeg2dec->buf_start, mpeg2dec->pending_length);
234 } else {
235 // still some data in the pending buffer, shouldn't happen
236 mpeg2dec->pending_length = mpeg2dec->buf_end - mpeg2dec->buf_start;
237 memmove(mpeg2dec->pending_buffer, mpeg2dec->buf_start, mpeg2dec->pending_length);
238 mpeg2dec->pending_buffer = realloc(mpeg2dec->pending_buffer, mpeg2dec->pending_length + len);
239 memcpy(mpeg2dec->pending_buffer+mpeg2dec->pending_length, data, len);
240 mpeg2dec->pending_length += len;
242 // fprintf(stderr, "pending = %d\n", mpeg2dec->pending_length);
243 return mpi;
248 #endif