cleanup: some random minor code simplification and cleanup
[mplayer/glamo.git] / libmpcodecs / dec_video.c
blob71d6de5216610413c55768d4466c1845fd216b16
1 /*
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.
19 #include "config.h"
20 #include "options.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <unistd.h>
27 #include "mp_msg.h"
29 #include "osdep/timer.h"
30 #include "osdep/shmem.h"
32 #include "stream/stream.h"
33 #include "libmpdemux/demuxer.h"
34 #include "libmpdemux/parse_es.h"
36 #include "codec-cfg.h"
38 #include "libvo/video_out.h"
40 #include "libmpdemux/stheader.h"
41 #include "vd.h"
42 #include "vf.h"
44 #include "dec_video.h"
46 #ifdef CONFIG_DYNAMIC_PLUGINS
47 #include <dlfcn.h>
48 #endif
50 // ===================================================================
52 extern double video_time_usage;
53 extern double vout_time_usage;
55 #include "cpudetect.h"
57 int field_dominance = -1;
59 int divx_quality = 0;
61 int get_video_quality_max(sh_video_t *sh_video)
63 vf_instance_t *vf = sh_video->vfilter;
64 if (vf) {
65 int ret = vf->control(vf, VFCTRL_QUERY_MAX_PP_LEVEL, NULL);
66 if (ret > 0) {
67 mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "[PP] Using external postprocessing filter, max q = %d.\n", ret);
68 return ret;
71 const struct vd_functions *vd = sh_video->vd_driver;
72 if (vd) {
73 int ret = vd->control(sh_video, VDCTRL_QUERY_MAX_PP_LEVEL, NULL);
74 if (ret > 0) {
75 mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "[PP] Using codec's postprocessing, max q = %d.\n", ret);
76 return ret;
79 return 0;
82 void set_video_quality(sh_video_t *sh_video, int quality)
84 vf_instance_t *vf = sh_video->vfilter;
85 if (vf) {
86 int ret = vf->control(vf, VFCTRL_SET_PP_LEVEL, (void *) (&quality));
87 if (ret == CONTROL_TRUE)
88 return; // success
90 const struct vd_functions *vd = sh_video->vd_driver;
91 if (vd)
92 vd->control(sh_video, VDCTRL_SET_PP_LEVEL, (void *) (&quality));
95 int set_video_colors(sh_video_t *sh_video, const char *item, int value)
97 vf_instance_t *vf = sh_video->vfilter;
98 vf_equalizer_t data;
100 data.item = item;
101 data.value = value;
103 mp_dbg(MSGT_DECVIDEO, MSGL_V, "set video colors %s=%d \n", item, value);
104 if (vf) {
105 int ret = vf->control(vf, VFCTRL_SET_EQUALIZER, &data);
106 if (ret == CONTROL_TRUE)
107 return 1;
109 /* try software control */
110 const struct vd_functions *vd = sh_video->vd_driver;
111 if (vd &&
112 vd->control(sh_video, VDCTRL_SET_EQUALIZER, item, (int *) value)
113 == CONTROL_OK)
114 return 1;
115 mp_tmsg(MSGT_DECVIDEO, MSGL_V, "Video attribute '%s' is not supported by selected vo & vd.\n",
116 item);
117 return 0;
120 int get_video_colors(sh_video_t *sh_video, const char *item, int *value)
122 vf_instance_t *vf = sh_video->vfilter;
123 vf_equalizer_t data;
125 data.item = item;
127 mp_dbg(MSGT_DECVIDEO, MSGL_V, "get video colors %s \n", item);
128 if (vf) {
129 int ret = vf->control(vf, VFCTRL_GET_EQUALIZER, &data);
130 if (ret == CONTROL_TRUE) {
131 *value = data.value;
132 return 1;
135 /* try software control */
136 const struct vd_functions *vd = sh_video->vd_driver;
137 if (vd)
138 return vd->control(sh_video, VDCTRL_GET_EQUALIZER, item, value);
139 return 0;
142 int set_rectangle(sh_video_t *sh_video, int param, int value)
144 vf_instance_t *vf = sh_video->vfilter;
145 int data[] = { param, value };
147 mp_dbg(MSGT_DECVIDEO, MSGL_V, "set rectangle \n");
148 if (vf) {
149 int ret = vf->control(vf, VFCTRL_CHANGE_RECTANGLE, data);
150 if (ret)
151 return 1;
153 return 0;
156 int redraw_osd(struct sh_video *sh_video, struct osd_state *osd)
158 struct vf_instance *vf = sh_video->vfilter;
159 if (vf->control(vf, VFCTRL_REDRAW_OSD, osd) == true)
160 return 0;
161 return -1;
164 void resync_video_stream(sh_video_t *sh_video)
166 const struct vd_functions *vd = sh_video->vd_driver;
167 if (vd)
168 vd->control(sh_video, VDCTRL_RESYNC_STREAM, NULL);
169 sh_video->prev_codec_reordered_pts = MP_NOPTS_VALUE;
170 sh_video->prev_sorted_pts = MP_NOPTS_VALUE;
173 int get_current_video_decoder_lag(sh_video_t *sh_video)
175 const struct vd_functions *vd = sh_video->vd_driver;
176 if (!vd)
177 return -1;
178 int ret = vd->control(sh_video, VDCTRL_QUERY_UNSEEN_FRAMES, NULL);
179 if (ret >= 10)
180 return ret - 10;
181 return -1;
184 void uninit_video(sh_video_t *sh_video)
186 if (!sh_video->initialized)
187 return;
188 mp_tmsg(MSGT_DECVIDEO, MSGL_V, "Uninit video: %s\n", sh_video->codec->drv);
189 sh_video->vd_driver->uninit(sh_video);
190 #ifdef CONFIG_DYNAMIC_PLUGINS
191 if (sh_video->dec_handle)
192 dlclose(sh_video->dec_handle);
193 #endif
194 vf_uninit_filter_chain(sh_video->vfilter);
195 sh_video->initialized = 0;
198 void vfm_help(void)
200 int i;
201 mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Available (compiled-in) video codec families/drivers:\n");
202 mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_DRIVERS\n");
203 mp_msg(MSGT_DECVIDEO, MSGL_INFO, " vfm: info: (comment)\n");
204 for (i = 0; mpcodecs_vd_drivers[i] != NULL; i++)
205 mp_msg(MSGT_DECVIDEO, MSGL_INFO, "%8s %s (%s)\n",
206 mpcodecs_vd_drivers[i]->info->short_name,
207 mpcodecs_vd_drivers[i]->info->name,
208 mpcodecs_vd_drivers[i]->info->comment);
211 static int init_video(sh_video_t *sh_video, char *codecname, char *vfm,
212 int status, stringset_t *selected)
214 int force = 0;
215 unsigned int orig_fourcc =
216 sh_video->bih ? sh_video->bih->biCompression : 0;
217 sh_video->codec = NULL;
218 sh_video->vf_initialized = 0;
219 if (codecname && codecname[0] == '+') {
220 codecname = &codecname[1];
221 force = 1;
224 while (1) {
225 int i;
226 int orig_w, orig_h;
227 // restore original fourcc:
228 if (sh_video->bih)
229 sh_video->bih->biCompression = orig_fourcc;
230 if (!
231 (sh_video->codec =
232 find_video_codec(sh_video->format,
233 sh_video->bih ? ((unsigned int *) &sh_video->
234 bih->biCompression) : NULL,
235 sh_video->codec, force)))
236 break;
237 // ok we found one codec
238 if (stringset_test(selected, sh_video->codec->name))
239 continue; // already tried & failed
240 if (codecname && strcmp(sh_video->codec->name, codecname))
241 continue; // -vc
242 if (vfm && strcmp(sh_video->codec->drv, vfm))
243 continue; // vfm doesn't match
244 if (!force && sh_video->codec->status < status)
245 continue; // too unstable
246 stringset_add(selected, sh_video->codec->name); // tagging it
247 // ok, it matches all rules, let's find the driver!
248 for (i = 0; mpcodecs_vd_drivers[i] != NULL; i++)
249 if (!strcmp(mpcodecs_vd_drivers[i]->info->short_name,
250 sh_video->codec->drv))
251 break;
252 sh_video->vd_driver = mpcodecs_vd_drivers[i];
253 #ifdef CONFIG_DYNAMIC_PLUGINS
254 if (!sh_video->vd_driver) {
255 /* try to open shared decoder plugin */
256 int buf_len;
257 char *buf;
258 vd_functions_t *funcs_sym;
259 vd_info_t *info_sym;
261 buf_len =
262 strlen(MPLAYER_LIBDIR) + strlen(sh_video->codec->drv) + 16;
263 buf = malloc(buf_len);
264 if (!buf)
265 break;
266 snprintf(buf, buf_len, "%s/mplayer/vd_%s.so", MPLAYER_LIBDIR,
267 sh_video->codec->drv);
268 mp_msg(MSGT_DECVIDEO, MSGL_DBG2,
269 "Trying to open external plugin: %s\n", buf);
270 sh_video->dec_handle = dlopen(buf, RTLD_LAZY);
271 if (!sh_video->dec_handle)
272 break;
273 snprintf(buf, buf_len, "mpcodecs_vd_%s", sh_video->codec->drv);
274 funcs_sym = dlsym(sh_video->dec_handle, buf);
275 if (!funcs_sym || !funcs_sym->info || !funcs_sym->init
276 || !funcs_sym->uninit || !funcs_sym->control
277 || !funcs_sym->decode)
278 break;
279 info_sym = funcs_sym->info;
280 if (strcmp(info_sym->short_name, sh_video->codec->drv))
281 break;
282 free(buf);
283 sh_video->vd_driver = funcs_sym;
284 mp_msg(MSGT_DECVIDEO, MSGL_V,
285 "Using external decoder plugin (%s/mplayer/vd_%s.so)!\n",
286 MPLAYER_LIBDIR, sh_video->codec->drv);
288 #endif
289 if (!sh_video->vd_driver) { // driver not available (==compiled in)
290 mp_tmsg(MSGT_DECVIDEO, MSGL_WARN,
291 _("Requested video codec family [%s] (vfm=%s) not available.\nEnable it at compilation.\n"),
292 sh_video->codec->name, sh_video->codec->drv);
293 continue;
295 orig_w = sh_video->bih ? sh_video->bih->biWidth : sh_video->disp_w;
296 orig_h = sh_video->bih ? sh_video->bih->biHeight : sh_video->disp_h;
297 sh_video->disp_w = orig_w;
298 sh_video->disp_h = orig_h;
299 // it's available, let's try to init!
300 if (sh_video->codec->flags & CODECS_FLAG_ALIGN16) {
301 // align width/height to n*16
302 sh_video->disp_w = (sh_video->disp_w + 15) & (~15);
303 sh_video->disp_h = (sh_video->disp_h + 15) & (~15);
305 if (sh_video->bih) {
306 sh_video->bih->biWidth = sh_video->disp_w;
307 sh_video->bih->biHeight = sh_video->disp_h;
310 // init()
311 const struct vd_functions *vd = sh_video->vd_driver;
312 mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Opening video decoder: [%s] %s\n",
313 vd->info->short_name, vd->info->name);
314 // clear vf init error, it is no longer relevant
315 if (sh_video->vf_initialized < 0)
316 sh_video->vf_initialized = 0;
317 if (!vd->init(sh_video)) {
318 mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "VDecoder init failed :(\n");
319 sh_video->disp_w = orig_w;
320 sh_video->disp_h = orig_h;
321 if (sh_video->bih) {
322 sh_video->bih->biWidth = sh_video->disp_w;
323 sh_video->bih->biHeight = sh_video->disp_h;
325 continue; // try next...
327 // Yeah! We got it!
328 sh_video->initialized = 1;
329 sh_video->prev_codec_reordered_pts = MP_NOPTS_VALUE;
330 sh_video->prev_sorted_pts = MP_NOPTS_VALUE;
331 return 1;
333 return 0;
336 int init_best_video_codec(sh_video_t *sh_video, char **video_codec_list,
337 char **video_fm_list)
339 char *vc_l_default[2] = { "", (char *) NULL };
340 stringset_t selected;
341 // hack:
342 if (!video_codec_list)
343 video_codec_list = vc_l_default;
344 // Go through the codec.conf and find the best codec...
345 sh_video->initialized = 0;
346 stringset_init(&selected);
347 while (!sh_video->initialized && *video_codec_list) {
348 char *video_codec = *(video_codec_list++);
349 if (video_codec[0]) {
350 if (video_codec[0] == '-') {
351 // disable this codec:
352 stringset_add(&selected, video_codec + 1);
353 } else {
354 // forced codec by name:
355 mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Forced video codec: %s\n",
356 video_codec);
357 init_video(sh_video, video_codec, NULL, -1, &selected);
359 } else {
360 int status;
361 // try in stability order: UNTESTED, WORKING, BUGGY. never try CRASHING.
362 if (video_fm_list) {
363 char **fmlist = video_fm_list;
364 // try first the preferred codec families:
365 while (!sh_video->initialized && *fmlist) {
366 char *video_fm = *(fmlist++);
367 mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Trying to force video codec driver family %s...\n",
368 video_fm);
369 for (status = CODECS_STATUS__MAX;
370 status >= CODECS_STATUS__MIN; --status)
371 if (init_video
372 (sh_video, NULL, video_fm, status, &selected))
373 break;
376 if (!sh_video->initialized)
377 for (status = CODECS_STATUS__MAX; status >= CODECS_STATUS__MIN;
378 --status)
379 if (init_video(sh_video, NULL, NULL, status, &selected))
380 break;
383 stringset_free(&selected);
385 if (!sh_video->initialized) {
386 mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Cannot find codec matching selected -vo and video format 0x%X.\n",
387 sh_video->format);
388 return 0; // failed
391 mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Selected video codec: [%s] vfm: %s (%s)\n",
392 sh_video->codec->name, sh_video->codec->drv, sh_video->codec->info);
393 return 1; // success
396 void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size,
397 int drop_frame, double pts)
399 mp_image_t *mpi = NULL;
400 unsigned int t = GetTimer();
401 unsigned int t2;
402 double tt;
403 struct MPOpts *opts = sh_video->opts;
405 if (opts->correct_pts && pts != MP_NOPTS_VALUE) {
406 int delay = get_current_video_decoder_lag(sh_video);
407 if (delay >= 0) {
408 if (delay > sh_video->num_buffered_pts)
409 #if 0
410 // this is disabled because vd_ffmpeg reports the same lag
411 // after seek even when there are no buffered frames,
412 // leading to incorrect error messages
413 mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Not enough buffered pts\n");
414 #else
416 #endif
417 else
418 sh_video->num_buffered_pts = delay;
420 if (sh_video->num_buffered_pts ==
421 sizeof(sh_video->buffered_pts) / sizeof(double))
422 mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Too many buffered pts\n");
423 else {
424 int i, j;
425 for (i = 0; i < sh_video->num_buffered_pts; i++)
426 if (sh_video->buffered_pts[i] < pts)
427 break;
428 for (j = sh_video->num_buffered_pts; j > i; j--)
429 sh_video->buffered_pts[j] = sh_video->buffered_pts[j - 1];
430 sh_video->buffered_pts[i] = pts;
431 sh_video->num_buffered_pts++;
435 if (sh_video->vd_driver->decode2) {
436 mpi = sh_video->vd_driver->decode2(sh_video, start, in_size,
437 drop_frame, &pts);
438 } else {
439 mpi = sh_video->vd_driver->decode(sh_video, start, in_size,
440 drop_frame);
441 pts = MP_NOPTS_VALUE;
444 //------------------------ frame decoded. --------------------
446 #if HAVE_MMX
447 // some codecs are broken, and doesn't restore MMX state :(
448 // it happens usually with broken/damaged files.
449 if (gCpuCaps.has3DNow) {
450 __asm__ volatile("femms\n\t":::"memory");
451 } else if (gCpuCaps.hasMMX) {
452 __asm__ volatile("emms\n\t":::"memory");
454 #endif
456 t2 = GetTimer();
457 t = t2 - t;
458 tt = t * 0.000001f;
459 video_time_usage += tt;
461 if (!mpi || drop_frame)
462 return NULL; // error / skipped frame
464 if (field_dominance == 0)
465 mpi->fields |= MP_IMGFIELD_TOP_FIRST;
466 else if (field_dominance == 1)
467 mpi->fields &= ~MP_IMGFIELD_TOP_FIRST;
469 double prevpts = sh_video->codec_reordered_pts;
470 sh_video->prev_codec_reordered_pts = prevpts;
471 sh_video->codec_reordered_pts = pts;
472 if (prevpts != MP_NOPTS_VALUE && pts <= prevpts
473 || pts == MP_NOPTS_VALUE)
474 sh_video->num_reordered_pts_problems++;
475 prevpts = sh_video->sorted_pts;
476 if (opts->correct_pts) {
477 if (sh_video->num_buffered_pts) {
478 sh_video->num_buffered_pts--;
479 sh_video->sorted_pts =
480 sh_video->buffered_pts[sh_video->num_buffered_pts];
481 } else {
482 mp_msg(MSGT_CPLAYER, MSGL_ERR,
483 "No pts value from demuxer to use for frame!\n");
484 sh_video->sorted_pts = MP_NOPTS_VALUE;
487 pts = sh_video->sorted_pts;
488 if (prevpts != MP_NOPTS_VALUE && pts <= prevpts
489 || pts == MP_NOPTS_VALUE)
490 sh_video->num_sorted_pts_problems++;
491 return mpi;
494 int filter_video(sh_video_t *sh_video, void *frame, double pts)
496 mp_image_t *mpi = frame;
497 unsigned int t2 = GetTimer();
498 vf_instance_t *vf = sh_video->vfilter;
499 // apply video filters and call the leaf vo/ve
500 int ret = vf->put_image(vf, mpi, pts);
502 t2 = GetTimer() - t2;
503 vout_time_usage += t2 * 0.000001;
505 return ret;