1 /*
2  * This file is part of MPlayer.
3  *
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.
8  *
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.
13  *
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.
17  */
18 
19 #include "config.h"
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 
25 #include "mp_msg.h"
26 #include "help_mp.h"
27 #include "mpcommon.h"
28 
29 #include "osdep/timer.h"
30 #include "osdep/shmem.h"
31 
32 #include "stream/stream.h"
33 #include "libmpdemux/demuxer.h"
34 #include "libmpdemux/parse_es.h"
35 
36 #include "codec-cfg.h"
37 
38 #include "libvo/video_out.h"
39 
40 #include "libmpdemux/stheader.h"
41 #include "vd.h"
42 #include "vf.h"
43 #include "sub/eosd.h"
44 
45 #include "dec_video.h"
46 
47 #ifdef CONFIG_DYNAMIC_PLUGINS
48 #include <dlfcn.h>
49 #endif
50 
51 #include "cpudetect.h"
52 
53 int field_dominance = -1;
54 
55 int divx_quality = 0;
56 
57 const vd_functions_t *mpvdec = NULL;
58 
get_video_quality_max(sh_video_t * sh_video)59 int get_video_quality_max(sh_video_t *sh_video)
60 {
61     vf_instance_t *vf = sh_video->vfilter;
62     if (vf) {
63         int ret = vf->control(vf, VFCTRL_QUERY_MAX_PP_LEVEL, NULL);
64         if (ret > 0) {
65             mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_UsingExternalPP, ret);
66             return ret;
67         }
68     }
69     if (mpvdec) {
70         int ret = mpvdec->control(sh_video, VDCTRL_QUERY_MAX_PP_LEVEL, NULL);
71         if (ret > 0) {
72             mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_UsingCodecPP, ret);
73             return ret;
74         }
75     }
76 //  mp_msg(MSGT_DECVIDEO,MSGL_INFO,"[PP] Sorry, postprocessing is not available\n");
77     return 0;
78 }
79 
set_video_quality(sh_video_t * sh_video,int quality)80 void set_video_quality(sh_video_t *sh_video, int quality)
81 {
82     vf_instance_t *vf = sh_video->vfilter;
83     if (vf) {
84         int ret = vf->control(vf, VFCTRL_SET_PP_LEVEL, &quality);
85         if (ret == CONTROL_TRUE)
86             return;             // success
87     }
88     if (mpvdec)
89         mpvdec->control(sh_video, VDCTRL_SET_PP_LEVEL, &quality);
90 }
91 
set_video_colors(sh_video_t * sh_video,const char * item,int value)92 int set_video_colors(sh_video_t *sh_video, const char *item, int value)
93 {
94     vf_instance_t *vf = sh_video->vfilter;
95     vf_equalizer_t data;
96 
97     data.item  = item;
98     data.value = value;
99 
100     mp_dbg(MSGT_DECVIDEO, MSGL_V, "set video colors %s=%d \n", item, value);
101     if (vf) {
102         int ret = vf->control(vf, VFCTRL_SET_EQUALIZER, &data);
103         if (ret == CONTROL_TRUE)
104             return 1;
105     }
106     /* try software control */
107     if (mpvdec)
108         if (mpvdec->control(sh_video, VDCTRL_SET_EQUALIZER, item,
109                             (int *) value) == CONTROL_OK)
110             return 1;
111     mp_msg(MSGT_DECVIDEO, MSGL_V,
112            "Video attribute '%s' is not supported by selected vo & vd.\n",
113            item);
114     return 0;
115 }
116 
get_video_colors(sh_video_t * sh_video,const char * item,int * value)117 int get_video_colors(sh_video_t *sh_video, const char *item, int *value)
118 {
119     vf_instance_t *vf = sh_video->vfilter;
120     vf_equalizer_t data;
121 
122     data.item = item;
123 
124     mp_dbg(MSGT_DECVIDEO, MSGL_V, "get video colors %s \n", item);
125     if (vf) {
126         int ret = vf->control(vf, VFCTRL_GET_EQUALIZER, &data);
127         if (ret == CONTROL_TRUE) {
128             *value = data.value;
129             return 1;
130         }
131     }
132     /* try software control */
133     if (mpvdec)
134         return mpvdec->control(sh_video, VDCTRL_GET_EQUALIZER, item, value);
135     return 0;
136 }
137 
set_rectangle(sh_video_t * sh_video,int param,int value)138 int set_rectangle(sh_video_t *sh_video, int param, int value)
139 {
140     vf_instance_t *vf = sh_video->vfilter;
141     int data[] = { param, value };
142 
143     mp_dbg(MSGT_DECVIDEO, MSGL_V, "set rectangle \n");
144     if (vf) {
145         int ret = vf->control(vf, VFCTRL_CHANGE_RECTANGLE, data);
146         if (ret)
147             return 1;
148     }
149     return 0;
150 }
151 
resync_video_stream(sh_video_t * sh_video)152 void resync_video_stream(sh_video_t *sh_video)
153 {
154     sh_video->timer            = 0;
155     sh_video->next_frame_time  = 0;
156     sh_video->num_buffered_pts = 0;
157     sh_video->last_pts         = MP_NOPTS_VALUE;
158     if (mpvdec)
159         mpvdec->control(sh_video, VDCTRL_RESYNC_STREAM, NULL);
160 }
161 
get_current_video_decoder_lag(sh_video_t * sh_video)162 int get_current_video_decoder_lag(sh_video_t *sh_video)
163 {
164     int ret;
165 
166     if (!mpvdec)
167         return -1;
168     ret = mpvdec->control(sh_video, VDCTRL_QUERY_UNSEEN_FRAMES, NULL);
169     if (ret >= 10)
170         return ret - 10;
171     return -1;
172 }
173 
uninit_video(sh_video_t * sh_video)174 void uninit_video(sh_video_t *sh_video)
175 {
176     if (!sh_video->initialized)
177         return;
178     mp_msg(MSGT_DECVIDEO, MSGL_V, "Uninit video: %s\n", codec_idx2str(sh_video->codec->drv_idx));
179     mpvdec->uninit(sh_video);
180     mpvdec = NULL;
181 #ifdef CONFIG_DYNAMIC_PLUGINS
182     if (sh_video->dec_handle)
183         dlclose(sh_video->dec_handle);
184 #endif
185     vf_uninit_filter_chain(sh_video->vfilter);
186     eosd_uninit();
187     sh_video->initialized = 0;
188 }
189 
vfm_help(void)190 void vfm_help(void)
191 {
192     int i;
193     mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_AvailableVideoFm);
194     mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_DRIVERS\n");
195     mp_msg(MSGT_DECVIDEO, MSGL_INFO, "   vfm:    info:  (comment)\n");
196     for (i = 0; mpcodecs_vd_drivers[i] != NULL; i++)
197         mp_msg(MSGT_DECVIDEO, MSGL_INFO, "%8s  %s (%s)\n",
198                mpcodecs_vd_drivers[i]->info->short_name,
199                mpcodecs_vd_drivers[i]->info->name,
200                mpcodecs_vd_drivers[i]->info->comment);
201 }
202 
init_video(sh_video_t * sh_video,char * codecname,char * vfm,int status,stringset_t * selected)203 static int init_video(sh_video_t *sh_video, char *codecname, char *vfm,
204                       int status, stringset_t *selected)
205 {
206     int force = 0;
207     unsigned int orig_fourcc = sh_video->bih ? sh_video->bih->biCompression : 0;
208     sh_video->codec = NULL;
209     sh_video->vf_initialized = 0;
210     if (codecname && codecname[0] == '+') {
211         codecname = &codecname[1];
212         force = 1;
213     }
214 
215     while (1) {
216         const char *drv;
217         int i;
218         int orig_w, orig_h;
219         // restore original fourcc:
220         if (sh_video->bih)
221             sh_video->bih->biCompression = orig_fourcc;
222         if (!(sh_video->codec =
223               find_video_codec(sh_video->format,
224                                sh_video->bih ? ((unsigned int *) &sh_video->bih->biCompression) : NULL,
225                                sh_video->codec, force)))
226             break;
227         drv = codec_idx2str(sh_video->codec->drv_idx);
228         // ok we found one codec
229         if (stringset_test(selected, codec_idx2str(sh_video->codec->name_idx)))
230             continue;           // already tried & failed
231         if (codecname && strcmp(codec_idx2str(sh_video->codec->name_idx), codecname))
232             continue;           // -vc
233         if (vfm && strcmp(drv, vfm))
234             continue;           // vfm doesn't match
235         if (!force && sh_video->codec->status < status)
236             continue;           // too unstable
237         stringset_add(selected, codec_idx2str(sh_video->codec->name_idx)); // tagging it
238         // ok, it matches all rules, let's find the driver!
239         for (i = 0; mpcodecs_vd_drivers[i] != NULL; i++)
240 //          if(mpcodecs_vd_drivers[i]->info->id==sh_video->codec->driver) break;
241             if (!strcmp
242                 (mpcodecs_vd_drivers[i]->info->short_name, drv))
243                 break;
244         mpvdec = mpcodecs_vd_drivers[i];
245 #ifdef CONFIG_DYNAMIC_PLUGINS
246         if (!mpvdec) {
247             /* try to open shared decoder plugin */
248             int buf_len;
249             char *buf;
250             vd_functions_t *funcs_sym;
251             vd_info_t *info_sym;
252 
253             buf_len = strlen(MPLAYER_LIBDIR) +
254                       strlen(drv) + 16;
255             buf = malloc(buf_len);
256             if (!buf)
257                 break;
258             snprintf(buf, buf_len, "%s/mplayer/vd_%s.so", MPLAYER_LIBDIR, drv);
259             mp_msg(MSGT_DECVIDEO, MSGL_DBG2,
260                    "Trying to open external plugin: %s\n", buf);
261             sh_video->dec_handle = dlopen(buf, RTLD_LAZY);
262             if (!sh_video->dec_handle)
263                 break;
264             snprintf(buf, buf_len, "mpcodecs_vd_%s", drv);
265             funcs_sym = dlsym(sh_video->dec_handle, buf);
266             if (!funcs_sym || !funcs_sym->info || !funcs_sym->init
267                 || !funcs_sym->uninit || !funcs_sym->control
268                 || !funcs_sym->decode)
269                 break;
270             info_sym = funcs_sym->info;
271             if (strcmp(info_sym->short_name, drv))
272                 break;
273             free(buf);
274             mpvdec = funcs_sym;
275             mp_msg(MSGT_DECVIDEO, MSGL_V,
276                    "Using external decoder plugin (%s/mplayer/vd_%s.so)!\n",
277                    MPLAYER_LIBDIR, drv);
278         }
279 #endif
280         if (!mpvdec) {          // driver not available (==compiled in)
281             mp_msg(MSGT_DECVIDEO, MSGL_WARN,
282                    MSGTR_VideoCodecFamilyNotAvailableStr,
283                    codec_idx2str(sh_video->codec->name_idx), drv);
284             continue;
285         }
286         /* only allow dummy codecs if specified via -vc */
287         if (sh_video->codec->flags & CODECS_FLAG_DUMMY && !codecname) {
288             continue;
289         }
290 
291         orig_w = sh_video->bih ? sh_video->bih->biWidth  : sh_video->disp_w;
292         orig_h = sh_video->bih ? sh_video->bih->biHeight : sh_video->disp_h;
293         sh_video->disp_w = orig_w;
294         sh_video->disp_h = orig_h;
295         // it's available, let's try to init!
296         if (sh_video->codec->flags & CODECS_FLAG_ALIGN16) {
297             // align width/height to n*16
298             sh_video->disp_w = (sh_video->disp_w + 15) & (~15);
299             sh_video->disp_h = (sh_video->disp_h + 15) & (~15);
300         }
301         if (sh_video->bih) {
302             sh_video->bih->biWidth  = sh_video->disp_w;
303             sh_video->bih->biHeight = sh_video->disp_h;
304         }
305         // init()
306         mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_OpeningVideoDecoder,
307                mpvdec->info->short_name, mpvdec->info->name);
308         // clear vf init error, it is no longer relevant
309         if (sh_video->vf_initialized < 0)
310             sh_video->vf_initialized = 0;
311         if (!mpvdec->init(sh_video)) {
312             mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_VDecoderInitFailed);
313             sh_video->disp_w = orig_w;
314             sh_video->disp_h = orig_h;
315             if (sh_video->bih) {
316                 sh_video->bih->biWidth  = sh_video->disp_w;
317                 sh_video->bih->biHeight = sh_video->disp_h;
318             }
319             continue;           // try next...
320         }
321         // Yeah! We got it!
322         sh_video->initialized = 1;
323         return 1;
324     }
325     return 0;
326 }
327 
init_best_video_codec(sh_video_t * sh_video,char ** video_codec_list,char ** video_fm_list)328 int init_best_video_codec(sh_video_t *sh_video, char **video_codec_list,
329                           char **video_fm_list)
330 {
331     char *vc_l_default[2] = { "", (char *) NULL };
332     stringset_t selected;
333     // hack:
334     if (!video_codec_list)
335         video_codec_list = vc_l_default;
336     // Go through the codec.conf and find the best codec...
337     sh_video->initialized = 0;
338     stringset_init(&selected);
339     while (!sh_video->initialized && *video_codec_list) {
340         char *video_codec = *(video_codec_list++);
341         if (video_codec[0]) {
342             if (video_codec[0] == '-') {
343                 // disable this codec:
344                 stringset_add(&selected, video_codec + 1);
345             } else {
346                 // forced codec by name:
347                 mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_ForcedVideoCodec,
348                        video_codec);
349                 init_video(sh_video, video_codec, NULL, -1, &selected);
350             }
351         } else {
352             int status;
353             // try in stability order: UNTESTED, WORKING, BUGGY. never try CRASHING.
354             if (video_fm_list) {
355                 char **fmlist = video_fm_list;
356                 // try first the preferred codec families:
357                 while (!sh_video->initialized && *fmlist) {
358                     char *video_fm = *(fmlist++);
359                     mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_TryForceVideoFmtStr,
360                            video_fm);
361                     for (status = CODECS_STATUS__MAX;
362                          status >= CODECS_STATUS__MIN; --status)
363                         if (init_video
364                             (sh_video, NULL, video_fm, status, &selected))
365                             break;
366                 }
367             }
368             if (!sh_video->initialized)
369                 for (status = CODECS_STATUS__MAX; status >= CODECS_STATUS__MIN;
370                      --status)
371                     if (init_video(sh_video, NULL, NULL, status, &selected))
372                         break;
373         }
374     }
375     stringset_free(&selected);
376 
377     if (!sh_video->initialized) {
378         mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_CantFindVideoCodec,
379                sh_video->format);
380         return 0;               // failed
381     }
382 
383     mp_msg(MSGT_DECVIDEO, MSGL_INFO, MSGTR_SelectedVideoCodec,
384            codec_idx2str(sh_video->codec->name_idx),
385            codec_idx2str(sh_video->codec->drv_idx),
386            codec_idx2str(sh_video->codec->info_idx));
387     return 1;                   // success
388 }
389 
decode_video(sh_video_t * sh_video,unsigned char * start,int in_size,int drop_frame,double pts,double endpts,int * full_frame)390 void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size,
391                    int drop_frame, double pts, double endpts, int *full_frame)
392 {
393     mp_image_t *mpi = NULL;
394     unsigned int t = GetTimer();
395     unsigned int t2;
396     double tt;
397     int delay;
398     int got_picture = 1;
399 
400     mpi = mpvdec->decode(sh_video, start, in_size, drop_frame);
401 
402     //------------------------ frame decoded. --------------------
403 
404     if (mpi && mpi->type == MP_IMGTYPE_INCOMPLETE) {
405 	got_picture = 0;
406 	mpi = NULL;
407     }
408 
409     if (full_frame)
410 	*full_frame = got_picture;
411 
412     delay = get_current_video_decoder_lag(sh_video);
413     if (correct_pts && pts != MP_NOPTS_VALUE
414         && (got_picture || sh_video->num_buffered_pts < delay)) {
415         if (sh_video->num_buffered_pts ==
416             sizeof(sh_video->buffered_pts) / sizeof(double))
417             mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Too many buffered pts\n");
418         else {
419             int i, j;
420             for (i = 0; i < sh_video->num_buffered_pts; i++)
421                 if (sh_video->buffered_pts[i] < pts)
422                     break;
423             for (j = sh_video->num_buffered_pts; j > i; j--) {
424                 sh_video->buffered_pts[j] = sh_video->buffered_pts[j - 1];
425                 sh_video->buffered_endpts[j] = sh_video->buffered_endpts[j - 1];
426             }
427             sh_video->buffered_pts[i] = pts;
428             sh_video->buffered_endpts[i] = endpts;
429             sh_video->num_buffered_pts++;
430         }
431     }
432     if (correct_pts && mpi && drop_frame && sh_video->num_buffered_pts > 0)
433         sh_video->num_buffered_pts--;
434 
435     // some codecs are broken, and doesn't restore MMX state :(
436     // it happens usually with broken/damaged files.
437 #if HAVE_INLINE_ASM
438     if (HAVE_AMD3DNOW_INLINE && gCpuCaps.has3DNow) {
439         __asm__ volatile ("femms\n\t":::"memory");
440     } else if (HAVE_MMX_INLINE && gCpuCaps.hasMMX) {
441         __asm__ volatile ("emms\n\t":::"memory");
442     }
443 #endif
444 
445     t2 = GetTimer();
446     t = t2 - t;
447     tt = t * 0.000001f;
448     video_time_usage += tt;
449 
450     if (!mpi || drop_frame)
451         return NULL;            // error / skipped frame
452 
453     if (field_dominance == 0)
454         mpi->fields |= MP_IMGFIELD_TOP_FIRST;
455     else if (field_dominance == 1)
456         mpi->fields &= ~MP_IMGFIELD_TOP_FIRST;
457 
458     if (correct_pts) {
459         if (sh_video->num_buffered_pts) {
460             sh_video->num_buffered_pts--;
461             sh_video->pts = sh_video->buffered_pts[sh_video->num_buffered_pts];
462             sh_video->endpts = sh_video->buffered_endpts[sh_video->num_buffered_pts];
463         } else {
464             mp_msg(MSGT_CPLAYER, MSGL_ERR,
465                    "No pts value from demuxer to use for frame!\n");
466             sh_video->pts = MP_NOPTS_VALUE;
467             sh_video->endpts = MP_NOPTS_VALUE;
468         }
469         if (delay >= 0) {
470             // limit buffered pts only afterwards so we do not get confused
471             // by packets that produce no output (e.g. a single field of a
472             // H.264 frame).
473             if (delay > sh_video->num_buffered_pts)
474 #if 0
475                 // this is disabled because vd_ffmpeg reports the same lag
476                 // after seek even when there are no buffered frames,
477                 // leading to incorrect error messages
478                 mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Not enough buffered pts\n");
479 #else
480                 ;
481 #endif
482             else
483                 sh_video->num_buffered_pts = delay;
484         }
485     }
486     return mpi;
487 }
488 
filter_video(sh_video_t * sh_video,void * frame,double pts,double endpts)489 int filter_video(sh_video_t *sh_video, void *frame, double pts, double endpts)
490 {
491     mp_image_t *mpi = frame;
492     unsigned int t2 = GetTimer();
493     vf_instance_t *vf = sh_video->vfilter;
494     // apply video filters and call the leaf vo/ve
495     int ret = vf->put_image(vf, mpi, pts, endpts);
496     if (ret > 0) {
497         // draw EOSD first so it ends up below the OSD.
498         // Note that changing this is will not work right with vf_ass and the
499         // vos currently always draw the EOSD first in paused mode.
500 #ifdef CONFIG_ASS
501         vf->control(vf, VFCTRL_DRAW_EOSD, NULL);
502 #endif
503         vf->control(vf, VFCTRL_DRAW_OSD, NULL);
504     }
505 
506     t2 = GetTimer() - t2;
507     vout_time_usage += t2 * 0.000001;
508 
509     return ret;
510 }
511