11 #include "osdep/timer.h"
12 #include "osdep/shmem.h"
14 #include "stream/stream.h"
15 #include "libmpdemux/demuxer.h"
16 #include "libmpdemux/parse_es.h"
18 #include "codec-cfg.h"
20 #include "libvo/video_out.h"
22 #include "libmpdemux/stheader.h"
26 #include "dec_video.h"
28 #ifdef CONFIG_DYNAMIC_PLUGINS
32 // ===================================================================
34 extern double video_time_usage
;
35 extern double vout_time_usage
;
37 #include "cpudetect.h"
39 int field_dominance
=-1;
43 vd_functions_t
* mpvdec
=NULL
;
45 int get_video_quality_max(sh_video_t
*sh_video
){
46 vf_instance_t
* vf
=sh_video
->vfilter
;
48 int ret
=vf
->control(vf
,VFCTRL_QUERY_MAX_PP_LEVEL
,NULL
);
50 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_UsingExternalPP
,ret
);
55 int ret
=mpvdec
->control(sh_video
,VDCTRL_QUERY_MAX_PP_LEVEL
,NULL
);
57 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_UsingCodecPP
,ret
);
61 // mp_msg(MSGT_DECVIDEO,MSGL_INFO,"[PP] Sorry, postprocessing is not available\n");
65 void set_video_quality(sh_video_t
*sh_video
,int quality
){
66 vf_instance_t
* vf
=sh_video
->vfilter
;
68 int ret
=vf
->control(vf
,VFCTRL_SET_PP_LEVEL
, (void*)(&quality
));
69 if(ret
==CONTROL_TRUE
) return; // success
72 mpvdec
->control(sh_video
,VDCTRL_SET_PP_LEVEL
, (void*)(&quality
));
75 int set_video_colors(sh_video_t
*sh_video
,const char *item
,int value
)
77 vf_instance_t
* vf
=sh_video
->vfilter
;
83 mp_dbg(MSGT_DECVIDEO
,MSGL_V
,"set video colors %s=%d \n", item
, value
);
86 int ret
= vf
->control(vf
, VFCTRL_SET_EQUALIZER
, &data
);
87 if (ret
== CONTROL_TRUE
)
90 /* try software control */
92 if( mpvdec
->control(sh_video
,VDCTRL_SET_EQUALIZER
, item
, (int *)value
)
93 == CONTROL_OK
) return 1;
94 mp_msg(MSGT_DECVIDEO
,MSGL_V
,MSGTR_VideoAttributeNotSupportedByVO_VD
,item
);
98 int get_video_colors(sh_video_t
*sh_video
,const char *item
,int *value
)
100 vf_instance_t
* vf
=sh_video
->vfilter
;
105 mp_dbg(MSGT_DECVIDEO
,MSGL_V
,"get video colors %s \n", item
);
108 int ret
= vf
->control(vf
, VFCTRL_GET_EQUALIZER
, &data
);
109 if (ret
== CONTROL_TRUE
){
114 /* try software control */
115 if(mpvdec
) return mpvdec
->control(sh_video
,VDCTRL_GET_EQUALIZER
, item
, value
);
119 int set_rectangle(sh_video_t
*sh_video
,int param
,int value
)
121 vf_instance_t
* vf
=sh_video
->vfilter
;
122 int data
[] = {param
, value
};
124 mp_dbg(MSGT_DECVIDEO
,MSGL_V
,"set rectangle \n");
127 int ret
= vf
->control(vf
, VFCTRL_CHANGE_RECTANGLE
, data
);
134 void resync_video_stream(sh_video_t
*sh_video
)
136 if(mpvdec
) mpvdec
->control(sh_video
, VDCTRL_RESYNC_STREAM
, NULL
);
139 int get_current_video_decoder_lag(sh_video_t
*sh_video
)
145 ret
= mpvdec
->control(sh_video
, VDCTRL_QUERY_UNSEEN_FRAMES
, NULL
);
151 void uninit_video(sh_video_t
*sh_video
){
152 if(!sh_video
->initialized
) return;
153 mp_msg(MSGT_DECVIDEO
,MSGL_V
,MSGTR_UninitVideoStr
,sh_video
->codec
->drv
);
154 mpvdec
->uninit(sh_video
);
155 #ifdef CONFIG_DYNAMIC_PLUGINS
156 if (sh_video
->dec_handle
)
157 dlclose(sh_video
->dec_handle
);
159 vf_uninit_filter_chain(sh_video
->vfilter
);
160 sh_video
->initialized
=0;
165 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_AvailableVideoFm
);
166 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_VIDEO_DRIVERS\n");
167 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
," vfm: info: (comment)\n");
168 for (i
=0; mpcodecs_vd_drivers
[i
] != NULL
; i
++)
169 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,"%8s %s (%s)\n",
170 mpcodecs_vd_drivers
[i
]->info
->short_name
,
171 mpcodecs_vd_drivers
[i
]->info
->name
,
172 mpcodecs_vd_drivers
[i
]->info
->comment
);
175 static int init_video(sh_video_t
*sh_video
,char* codecname
,char* vfm
,int status
,
176 stringset_t
*selected
){
178 unsigned int orig_fourcc
=sh_video
->bih
?sh_video
->bih
->biCompression
:0;
179 sh_video
->codec
=NULL
;
180 sh_video
->vf_initialized
=0;
181 if (codecname
&& codecname
[0] == '+') {
182 codecname
= &codecname
[1];
189 // restore original fourcc:
190 if(sh_video
->bih
) sh_video
->bih
->biCompression
=orig_fourcc
;
191 if(!(sh_video
->codec
=find_video_codec(sh_video
->format
,
192 sh_video
->bih
?((unsigned int*) &sh_video
->bih
->biCompression
):NULL
,
193 sh_video
->codec
,force
) )) break;
194 // ok we found one codec
195 if(stringset_test(selected
, sh_video
->codec
->name
)) continue; // already tried & failed
196 if(codecname
&& strcmp(sh_video
->codec
->name
,codecname
)) continue; // -vc
197 if(vfm
&& strcmp(sh_video
->codec
->drv
,vfm
)) continue; // vfm doesn't match
198 if(!force
&& sh_video
->codec
->status
<status
) continue; // too unstable
199 stringset_add(selected
, sh_video
->codec
->name
); // tagging it
200 // ok, it matches all rules, let's find the driver!
201 for (i
=0; mpcodecs_vd_drivers
[i
] != NULL
; i
++)
202 // if(mpcodecs_vd_drivers[i]->info->id==sh_video->codec->driver) break;
203 if(!strcmp(mpcodecs_vd_drivers
[i
]->info
->short_name
,sh_video
->codec
->drv
)) break;
204 mpvdec
=mpcodecs_vd_drivers
[i
];
205 #ifdef CONFIG_DYNAMIC_PLUGINS
208 /* try to open shared decoder plugin */
211 vd_functions_t
*funcs_sym
;
214 buf_len
= strlen(MPLAYER_LIBDIR
)+strlen(sh_video
->codec
->drv
)+16;
215 buf
= malloc(buf_len
);
218 snprintf(buf
, buf_len
, "%s/mplayer/vd_%s.so", MPLAYER_LIBDIR
, sh_video
->codec
->drv
);
219 mp_msg(MSGT_DECVIDEO
, MSGL_DBG2
, "Trying to open external plugin: %s\n", buf
);
220 sh_video
->dec_handle
= dlopen(buf
, RTLD_LAZY
);
221 if (!sh_video
->dec_handle
)
223 snprintf(buf
, buf_len
, "mpcodecs_vd_%s", sh_video
->codec
->drv
);
224 funcs_sym
= dlsym(sh_video
->dec_handle
, buf
);
225 if (!funcs_sym
|| !funcs_sym
->info
|| !funcs_sym
->init
||
226 !funcs_sym
->uninit
|| !funcs_sym
->control
|| !funcs_sym
->decode
)
228 info_sym
= funcs_sym
->info
;
229 if (strcmp(info_sym
->short_name
, sh_video
->codec
->drv
))
233 mp_msg(MSGT_DECVIDEO
, MSGL_V
, "Using external decoder plugin (%s/mplayer/vd_%s.so)!\n",
234 MPLAYER_LIBDIR
, sh_video
->codec
->drv
);
237 if(!mpvdec
){ // driver not available (==compiled in)
238 mp_msg(MSGT_DECVIDEO
,MSGL_WARN
,MSGTR_VideoCodecFamilyNotAvailableStr
,
239 sh_video
->codec
->name
, sh_video
->codec
->drv
);
242 orig_w
= sh_video
->bih
? sh_video
->bih
->biWidth
: sh_video
->disp_w
;
243 orig_h
= sh_video
->bih
? sh_video
->bih
->biHeight
: sh_video
->disp_h
;
244 sh_video
->disp_w
= orig_w
;
245 sh_video
->disp_h
= orig_h
;
246 // it's available, let's try to init!
247 if(sh_video
->codec
->flags
& CODECS_FLAG_ALIGN16
){
248 // align width/height to n*16
249 sh_video
->disp_w
=(sh_video
->disp_w
+15)&(~15);
250 sh_video
->disp_h
=(sh_video
->disp_h
+15)&(~15);
253 sh_video
->bih
->biWidth
= sh_video
->disp_w
;
254 sh_video
->bih
->biHeight
= sh_video
->disp_h
;
257 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_OpeningVideoDecoder
,mpvdec
->info
->short_name
,mpvdec
->info
->name
);
258 // clear vf init error, it is no longer relevant
259 if (sh_video
->vf_initialized
< 0)
260 sh_video
->vf_initialized
= 0;
261 if(!mpvdec
->init(sh_video
)){
262 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_VDecoderInitFailed
);
263 sh_video
->disp_w
=orig_w
;
264 sh_video
->disp_h
=orig_h
;
266 sh_video
->bih
->biWidth
= sh_video
->disp_w
;
267 sh_video
->bih
->biHeight
= sh_video
->disp_h
;
269 continue; // try next...
272 sh_video
->initialized
=1;
278 int init_best_video_codec(sh_video_t
*sh_video
,char** video_codec_list
,char** video_fm_list
){
279 char* vc_l_default
[2]={"",(char*)NULL
};
280 stringset_t selected
;
282 if(!video_codec_list
) video_codec_list
=vc_l_default
;
283 // Go through the codec.conf and find the best codec...
284 sh_video
->initialized
=0;
285 stringset_init(&selected
);
286 while(!sh_video
->initialized
&& *video_codec_list
){
287 char* video_codec
=*(video_codec_list
++);
289 if(video_codec
[0]=='-'){
290 // disable this codec:
291 stringset_add(&selected
, video_codec
+1);
293 // forced codec by name:
294 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_ForcedVideoCodec
,video_codec
);
295 init_video(sh_video
,video_codec
,NULL
,-1, &selected
);
299 // try in stability order: UNTESTED, WORKING, BUGGY. never try CRASHING.
301 char** fmlist
=video_fm_list
;
302 // try first the preferred codec families:
303 while(!sh_video
->initialized
&& *fmlist
){
304 char* video_fm
=*(fmlist
++);
305 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_TryForceVideoFmtStr
,video_fm
);
306 for(status
=CODECS_STATUS__MAX
;status
>=CODECS_STATUS__MIN
;--status
)
307 if(init_video(sh_video
,NULL
,video_fm
,status
, &selected
)) break;
310 if(!sh_video
->initialized
)
311 for(status
=CODECS_STATUS__MAX
;status
>=CODECS_STATUS__MIN
;--status
)
312 if(init_video(sh_video
,NULL
,NULL
,status
, &selected
)) break;
315 stringset_free(&selected
);
317 if(!sh_video
->initialized
){
318 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,MSGTR_CantFindVideoCodec
,sh_video
->format
);
322 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_SelectedVideoCodec
,
323 sh_video
->codec
->name
,sh_video
->codec
->drv
,sh_video
->codec
->info
);
327 void *decode_video(sh_video_t
*sh_video
, unsigned char *start
, int in_size
,
328 int drop_frame
, double pts
)
330 mp_image_t
*mpi
= NULL
;
331 unsigned int t
= GetTimer();
335 if (correct_pts
&& pts
!= MP_NOPTS_VALUE
) {
336 int delay
= get_current_video_decoder_lag(sh_video
);
338 if (delay
> sh_video
->num_buffered_pts
)
340 // this is disabled because vd_ffmpeg reports the same lag
341 // after seek even when there are no buffered frames,
342 // leading to incorrect error messages
343 mp_msg(MSGT_DECVIDEO
, MSGL_ERR
, "Not enough buffered pts\n");
348 sh_video
->num_buffered_pts
= delay
;
350 if (sh_video
->num_buffered_pts
==
351 sizeof(sh_video
->buffered_pts
)/sizeof(double))
352 mp_msg(MSGT_DECVIDEO
, MSGL_ERR
, "Too many buffered pts\n");
355 for (i
= 0; i
< sh_video
->num_buffered_pts
; i
++)
356 if (sh_video
->buffered_pts
[i
] < pts
)
358 for (j
= sh_video
->num_buffered_pts
; j
> i
; j
--)
359 sh_video
->buffered_pts
[j
] = sh_video
->buffered_pts
[j
-1];
360 sh_video
->buffered_pts
[i
] = pts
;
361 sh_video
->num_buffered_pts
++;
365 mpi
= mpvdec
->decode(sh_video
, start
, in_size
, drop_frame
);
367 //------------------------ frame decoded. --------------------
370 // some codecs are broken, and doesn't restore MMX state :(
371 // it happens usually with broken/damaged files.
372 if (gCpuCaps
.has3DNow
) {
373 __asm__
volatile ("femms\n\t":::"memory");
375 else if (gCpuCaps
.hasMMX
) {
376 __asm__
volatile ("emms\n\t":::"memory");
380 t2
= GetTimer(); t
= t2
-t
;
382 video_time_usage
+= tt
;
384 if (!mpi
|| drop_frame
)
385 return NULL
; // error / skipped frame
387 if (field_dominance
== 0)
388 mpi
->fields
|= MP_IMGFIELD_TOP_FIRST
;
389 else if (field_dominance
== 1)
390 mpi
->fields
&= ~MP_IMGFIELD_TOP_FIRST
;
393 if (sh_video
->num_buffered_pts
) {
394 sh_video
->num_buffered_pts
--;
395 sh_video
->pts
= sh_video
->buffered_pts
[sh_video
->num_buffered_pts
];
398 mp_msg(MSGT_CPLAYER
, MSGL_ERR
, "No pts value from demuxer to "
400 sh_video
->pts
= MP_NOPTS_VALUE
;
406 int filter_video(sh_video_t
*sh_video
, void *frame
, double pts
)
408 mp_image_t
*mpi
= frame
;
409 unsigned int t2
= GetTimer();
410 vf_instance_t
*vf
= sh_video
->vfilter
;
411 // apply video filters and call the leaf vo/ve
412 int ret
= vf
->put_image(vf
, mpi
, pts
);
414 // draw EOSD first so it ends up below the OSD.
415 // Note that changing this is will not work right with vf_ass and the
416 // vos currently always draw the EOSD first in paused mode.
418 vf
->control(vf
, VFCTRL_DRAW_EOSD
, NULL
);
420 vf
->control(vf
, VFCTRL_DRAW_OSD
, NULL
);
424 vout_time_usage
+= t2
*0.000001;