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.
28 #include "osdep/timer.h"
29 #include "osdep/shmem.h"
31 #include "stream/stream.h"
32 #include "libmpdemux/demuxer.h"
33 #include "libmpdemux/parse_es.h"
35 #include "codec-cfg.h"
37 #include "libvo/video_out.h"
39 #include "libmpdemux/stheader.h"
43 #include "dec_video.h"
45 #ifdef CONFIG_DYNAMIC_PLUGINS
49 // ===================================================================
51 extern double video_time_usage
;
52 extern double vout_time_usage
;
54 #include "cpudetect.h"
56 int field_dominance
=-1;
60 const vd_functions_t
* mpvdec
=NULL
;
62 int get_video_quality_max(sh_video_t
*sh_video
){
63 vf_instance_t
* vf
=sh_video
->vfilter
;
65 int ret
=vf
->control(vf
,VFCTRL_QUERY_MAX_PP_LEVEL
,NULL
);
67 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_UsingExternalPP
,ret
);
72 int ret
=mpvdec
->control(sh_video
,VDCTRL_QUERY_MAX_PP_LEVEL
,NULL
);
74 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_UsingCodecPP
,ret
);
78 // mp_msg(MSGT_DECVIDEO,MSGL_INFO,"[PP] Sorry, postprocessing is not available\n");
82 void set_video_quality(sh_video_t
*sh_video
,int quality
){
83 vf_instance_t
* vf
=sh_video
->vfilter
;
85 int ret
=vf
->control(vf
,VFCTRL_SET_PP_LEVEL
, (void*)(&quality
));
86 if(ret
==CONTROL_TRUE
) return; // success
89 mpvdec
->control(sh_video
,VDCTRL_SET_PP_LEVEL
, (void*)(&quality
));
92 int set_video_colors(sh_video_t
*sh_video
,const char *item
,int value
)
94 vf_instance_t
* vf
=sh_video
->vfilter
;
100 mp_dbg(MSGT_DECVIDEO
,MSGL_V
,"set video colors %s=%d \n", item
, value
);
103 int ret
= vf
->control(vf
, VFCTRL_SET_EQUALIZER
, &data
);
104 if (ret
== CONTROL_TRUE
)
107 /* try software control */
109 if( mpvdec
->control(sh_video
,VDCTRL_SET_EQUALIZER
, item
, (int *)value
)
110 == CONTROL_OK
) return 1;
111 mp_msg(MSGT_DECVIDEO
,MSGL_V
,MSGTR_VideoAttributeNotSupportedByVO_VD
,item
);
115 int get_video_colors(sh_video_t
*sh_video
,const char *item
,int *value
)
117 vf_instance_t
* vf
=sh_video
->vfilter
;
122 mp_dbg(MSGT_DECVIDEO
,MSGL_V
,"get video colors %s \n", item
);
125 int ret
= vf
->control(vf
, VFCTRL_GET_EQUALIZER
, &data
);
126 if (ret
== CONTROL_TRUE
){
131 /* try software control */
132 if(mpvdec
) return mpvdec
->control(sh_video
,VDCTRL_GET_EQUALIZER
, item
, value
);
136 int set_rectangle(sh_video_t
*sh_video
,int param
,int value
)
138 vf_instance_t
* vf
=sh_video
->vfilter
;
139 int data
[] = {param
, value
};
141 mp_dbg(MSGT_DECVIDEO
,MSGL_V
,"set rectangle \n");
144 int ret
= vf
->control(vf
, VFCTRL_CHANGE_RECTANGLE
, data
);
151 void resync_video_stream(sh_video_t
*sh_video
)
154 sh_video
->next_frame_time
= 0;
155 sh_video
->num_buffered_pts
= 0;
156 sh_video
->last_pts
= MP_NOPTS_VALUE
;
157 if(mpvdec
) mpvdec
->control(sh_video
, VDCTRL_RESYNC_STREAM
, NULL
);
160 int get_current_video_decoder_lag(sh_video_t
*sh_video
)
166 ret
= mpvdec
->control(sh_video
, VDCTRL_QUERY_UNSEEN_FRAMES
, NULL
);
172 void uninit_video(sh_video_t
*sh_video
){
173 if(!sh_video
->initialized
) return;
174 mp_msg(MSGT_DECVIDEO
,MSGL_V
,MSGTR_UninitVideoStr
,sh_video
->codec
->drv
);
175 mpvdec
->uninit(sh_video
);
176 #ifdef CONFIG_DYNAMIC_PLUGINS
177 if (sh_video
->dec_handle
)
178 dlclose(sh_video
->dec_handle
);
180 vf_uninit_filter_chain(sh_video
->vfilter
);
181 sh_video
->initialized
=0;
186 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_AvailableVideoFm
);
187 mp_msg(MSGT_IDENTIFY
, MSGL_INFO
, "ID_VIDEO_DRIVERS\n");
188 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
," vfm: info: (comment)\n");
189 for (i
=0; mpcodecs_vd_drivers
[i
] != NULL
; i
++)
190 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,"%8s %s (%s)\n",
191 mpcodecs_vd_drivers
[i
]->info
->short_name
,
192 mpcodecs_vd_drivers
[i
]->info
->name
,
193 mpcodecs_vd_drivers
[i
]->info
->comment
);
196 static int init_video(sh_video_t
*sh_video
,char* codecname
,char* vfm
,int status
,
197 stringset_t
*selected
){
199 unsigned int orig_fourcc
=sh_video
->bih
?sh_video
->bih
->biCompression
:0;
200 sh_video
->codec
=NULL
;
201 sh_video
->vf_initialized
=0;
202 if (codecname
&& codecname
[0] == '+') {
203 codecname
= &codecname
[1];
210 // restore original fourcc:
211 if(sh_video
->bih
) sh_video
->bih
->biCompression
=orig_fourcc
;
212 if(!(sh_video
->codec
=find_video_codec(sh_video
->format
,
213 sh_video
->bih
?((unsigned int*) &sh_video
->bih
->biCompression
):NULL
,
214 sh_video
->codec
,force
) )) break;
215 // ok we found one codec
216 if(stringset_test(selected
, sh_video
->codec
->name
)) continue; // already tried & failed
217 if(codecname
&& strcmp(sh_video
->codec
->name
,codecname
)) continue; // -vc
218 if(vfm
&& strcmp(sh_video
->codec
->drv
,vfm
)) continue; // vfm doesn't match
219 if(!force
&& sh_video
->codec
->status
<status
) continue; // too unstable
220 stringset_add(selected
, sh_video
->codec
->name
); // tagging it
221 // ok, it matches all rules, let's find the driver!
222 for (i
=0; mpcodecs_vd_drivers
[i
] != NULL
; i
++)
223 // if(mpcodecs_vd_drivers[i]->info->id==sh_video->codec->driver) break;
224 if(!strcmp(mpcodecs_vd_drivers
[i
]->info
->short_name
,sh_video
->codec
->drv
)) break;
225 mpvdec
=mpcodecs_vd_drivers
[i
];
226 #ifdef CONFIG_DYNAMIC_PLUGINS
229 /* try to open shared decoder plugin */
232 vd_functions_t
*funcs_sym
;
235 buf_len
= strlen(MPLAYER_LIBDIR
)+strlen(sh_video
->codec
->drv
)+16;
236 buf
= malloc(buf_len
);
239 snprintf(buf
, buf_len
, "%s/mplayer/vd_%s.so", MPLAYER_LIBDIR
, sh_video
->codec
->drv
);
240 mp_msg(MSGT_DECVIDEO
, MSGL_DBG2
, "Trying to open external plugin: %s\n", buf
);
241 sh_video
->dec_handle
= dlopen(buf
, RTLD_LAZY
);
242 if (!sh_video
->dec_handle
)
244 snprintf(buf
, buf_len
, "mpcodecs_vd_%s", sh_video
->codec
->drv
);
245 funcs_sym
= dlsym(sh_video
->dec_handle
, buf
);
246 if (!funcs_sym
|| !funcs_sym
->info
|| !funcs_sym
->init
||
247 !funcs_sym
->uninit
|| !funcs_sym
->control
|| !funcs_sym
->decode
)
249 info_sym
= funcs_sym
->info
;
250 if (strcmp(info_sym
->short_name
, sh_video
->codec
->drv
))
254 mp_msg(MSGT_DECVIDEO
, MSGL_V
, "Using external decoder plugin (%s/mplayer/vd_%s.so)!\n",
255 MPLAYER_LIBDIR
, sh_video
->codec
->drv
);
258 if(!mpvdec
){ // driver not available (==compiled in)
259 mp_msg(MSGT_DECVIDEO
,MSGL_WARN
,MSGTR_VideoCodecFamilyNotAvailableStr
,
260 sh_video
->codec
->name
, sh_video
->codec
->drv
);
263 orig_w
= sh_video
->bih
? sh_video
->bih
->biWidth
: sh_video
->disp_w
;
264 orig_h
= sh_video
->bih
? sh_video
->bih
->biHeight
: sh_video
->disp_h
;
265 sh_video
->disp_w
= orig_w
;
266 sh_video
->disp_h
= orig_h
;
267 // it's available, let's try to init!
268 if(sh_video
->codec
->flags
& CODECS_FLAG_ALIGN16
){
269 // align width/height to n*16
270 sh_video
->disp_w
=(sh_video
->disp_w
+15)&(~15);
271 sh_video
->disp_h
=(sh_video
->disp_h
+15)&(~15);
274 sh_video
->bih
->biWidth
= sh_video
->disp_w
;
275 sh_video
->bih
->biHeight
= sh_video
->disp_h
;
278 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_OpeningVideoDecoder
,mpvdec
->info
->short_name
,mpvdec
->info
->name
);
279 // clear vf init error, it is no longer relevant
280 if (sh_video
->vf_initialized
< 0)
281 sh_video
->vf_initialized
= 0;
282 if(!mpvdec
->init(sh_video
)){
283 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_VDecoderInitFailed
);
284 sh_video
->disp_w
=orig_w
;
285 sh_video
->disp_h
=orig_h
;
287 sh_video
->bih
->biWidth
= sh_video
->disp_w
;
288 sh_video
->bih
->biHeight
= sh_video
->disp_h
;
290 continue; // try next...
293 sh_video
->initialized
=1;
299 int init_best_video_codec(sh_video_t
*sh_video
,char** video_codec_list
,char** video_fm_list
){
300 char* vc_l_default
[2]={"",(char*)NULL
};
301 stringset_t selected
;
303 if(!video_codec_list
) video_codec_list
=vc_l_default
;
304 // Go through the codec.conf and find the best codec...
305 sh_video
->initialized
=0;
306 stringset_init(&selected
);
307 while(!sh_video
->initialized
&& *video_codec_list
){
308 char* video_codec
=*(video_codec_list
++);
310 if(video_codec
[0]=='-'){
311 // disable this codec:
312 stringset_add(&selected
, video_codec
+1);
314 // forced codec by name:
315 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_ForcedVideoCodec
,video_codec
);
316 init_video(sh_video
,video_codec
,NULL
,-1, &selected
);
320 // try in stability order: UNTESTED, WORKING, BUGGY. never try CRASHING.
322 char** fmlist
=video_fm_list
;
323 // try first the preferred codec families:
324 while(!sh_video
->initialized
&& *fmlist
){
325 char* video_fm
=*(fmlist
++);
326 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_TryForceVideoFmtStr
,video_fm
);
327 for(status
=CODECS_STATUS__MAX
;status
>=CODECS_STATUS__MIN
;--status
)
328 if(init_video(sh_video
,NULL
,video_fm
,status
, &selected
)) break;
331 if(!sh_video
->initialized
)
332 for(status
=CODECS_STATUS__MAX
;status
>=CODECS_STATUS__MIN
;--status
)
333 if(init_video(sh_video
,NULL
,NULL
,status
, &selected
)) break;
336 stringset_free(&selected
);
338 if(!sh_video
->initialized
){
339 mp_msg(MSGT_DECVIDEO
,MSGL_ERR
,MSGTR_CantFindVideoCodec
,sh_video
->format
);
343 mp_msg(MSGT_DECVIDEO
,MSGL_INFO
,MSGTR_SelectedVideoCodec
,
344 sh_video
->codec
->name
,sh_video
->codec
->drv
,sh_video
->codec
->info
);
348 void *decode_video(sh_video_t
*sh_video
, unsigned char *start
, int in_size
,
349 int drop_frame
, double pts
)
351 mp_image_t
*mpi
= NULL
;
352 unsigned int t
= GetTimer();
356 if (correct_pts
&& pts
!= MP_NOPTS_VALUE
) {
357 int delay
= get_current_video_decoder_lag(sh_video
);
359 if (delay
> sh_video
->num_buffered_pts
)
361 // this is disabled because vd_ffmpeg reports the same lag
362 // after seek even when there are no buffered frames,
363 // leading to incorrect error messages
364 mp_msg(MSGT_DECVIDEO
, MSGL_ERR
, "Not enough buffered pts\n");
369 sh_video
->num_buffered_pts
= delay
;
371 if (sh_video
->num_buffered_pts
==
372 sizeof(sh_video
->buffered_pts
)/sizeof(double))
373 mp_msg(MSGT_DECVIDEO
, MSGL_ERR
, "Too many buffered pts\n");
376 for (i
= 0; i
< sh_video
->num_buffered_pts
; i
++)
377 if (sh_video
->buffered_pts
[i
] < pts
)
379 for (j
= sh_video
->num_buffered_pts
; j
> i
; j
--)
380 sh_video
->buffered_pts
[j
] = sh_video
->buffered_pts
[j
-1];
381 sh_video
->buffered_pts
[i
] = pts
;
382 sh_video
->num_buffered_pts
++;
386 mpi
= mpvdec
->decode(sh_video
, start
, in_size
, drop_frame
);
388 //------------------------ frame decoded. --------------------
391 // some codecs are broken, and doesn't restore MMX state :(
392 // it happens usually with broken/damaged files.
393 if (gCpuCaps
.has3DNow
) {
394 __asm__
volatile ("femms\n\t":::"memory");
396 else if (gCpuCaps
.hasMMX
) {
397 __asm__
volatile ("emms\n\t":::"memory");
401 t2
= GetTimer(); t
= t2
-t
;
403 video_time_usage
+= tt
;
405 if (!mpi
|| drop_frame
)
406 return NULL
; // error / skipped frame
408 if (field_dominance
== 0)
409 mpi
->fields
|= MP_IMGFIELD_TOP_FIRST
;
410 else if (field_dominance
== 1)
411 mpi
->fields
&= ~MP_IMGFIELD_TOP_FIRST
;
414 if (sh_video
->num_buffered_pts
) {
415 sh_video
->num_buffered_pts
--;
416 sh_video
->pts
= sh_video
->buffered_pts
[sh_video
->num_buffered_pts
];
419 mp_msg(MSGT_CPLAYER
, MSGL_ERR
, "No pts value from demuxer to "
421 sh_video
->pts
= MP_NOPTS_VALUE
;
427 int filter_video(sh_video_t
*sh_video
, void *frame
, double pts
)
429 mp_image_t
*mpi
= frame
;
430 unsigned int t2
= GetTimer();
431 vf_instance_t
*vf
= sh_video
->vfilter
;
432 // apply video filters and call the leaf vo/ve
433 int ret
= vf
->put_image(vf
, mpi
, pts
);
435 // draw EOSD first so it ends up below the OSD.
436 // Note that changing this is will not work right with vf_ass and the
437 // vos currently always draw the EOSD first in paused mode.
439 vf
->control(vf
, VFCTRL_DRAW_EOSD
, NULL
);
441 vf
->control(vf
, VFCTRL_DRAW_OSD
, NULL
);
445 vout_time_usage
+= t2
*0.000001;