summaryrefslogtreecommitdiff
path: root/src/dxr3/dxr3_decode_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dxr3/dxr3_decode_video.c')
-rw-r--r--src/dxr3/dxr3_decode_video.c186
1 files changed, 95 insertions, 91 deletions
diff --git a/src/dxr3/dxr3_decode_video.c b/src/dxr3/dxr3_decode_video.c
index 3f1c273ff..75a371566 100644
--- a/src/dxr3/dxr3_decode_video.c
+++ b/src/dxr3/dxr3_decode_video.c
@@ -1,23 +1,27 @@
-/*
+/*
* Copyright (C) 2000-2003 the xine project
- *
+ *
* This file is part of xine, a free video player.
- *
+ *
* xine is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* xine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
*/
-
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
/* dxr3 video decoder plugin.
* Accepts the video data from xine and sends it directly to the
* corresponding dxr3 device. Takes precedence over the libmpeg2
@@ -73,7 +77,7 @@ static const decoder_info_t dxr3_video_decoder_info = {
};
const plugin_info_t xine_plugin_info[] EXPORTED = {
- /* type, API, "name", version, special_info, init_function */
+ /* type, API, "name", version, special_info, init_function */
{ PLUGIN_VIDEO_DECODER, 18, "dxr3-mpeg2", XINE_VERSION_CODE, &dxr3_video_decoder_info, &dxr3_init_plugin },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};
@@ -95,9 +99,9 @@ static void dxr3_dispose(video_decoder_t *this_gen);
/* plugin structures */
typedef struct dxr3_decoder_class_s {
video_decoder_class_t video_decoder_class;
-
+
int instance; /* we allow only one instance of this plugin */
-
+
metronom_clock_t *clock; /* used for syncing */
} dxr3_decoder_class_t;
@@ -106,11 +110,11 @@ typedef struct dxr3_decoder_s {
dxr3_decoder_class_t *class;
xine_stream_t *stream;
dxr3_scr_t *scr; /* shortcut to the scr plugin in the dxr3 video out */
-
+
int devnum;
int fd_control;
int fd_video; /* to access the dxr3 devices */
-
+
int have_header_info;
int sequence_open;
int width;
@@ -119,26 +123,26 @@ typedef struct dxr3_decoder_s {
int aspect_code;
int frame_rate_code;
int repeat_first_field; /* mpeg stream header data */
-
+
int force_aspect; /* when input plugin has better info, we are forced */
int force_pan_scan; /* to use a certain aspect or to do pan&scan */
-
+
int use_panscan;
int panscan_smart_change;
int afd_smart_change;
int afd_code; /* use pan&scan info if present in stream */
-
+
int last_width;
int last_height;
int last_aspect_code; /* used to detect changes for event sending */
-
+
unsigned int dts_offset[3];
int sync_every_frame;
int sync_retry;
int enhanced_mode;
int resync_window;
int skip_count; /* syncing parameters */
-
+
int correct_durations;
int64_t last_vpts;
int force_duration_window;
@@ -164,7 +168,7 @@ static inline int dxr3_present(xine_stream_t *stream)
plugin_node_t *node;
video_driver_class_t *vo_class;
int present = 0;
-
+
if (stream->video_driver && stream->video_driver->node) {
node = (plugin_node_t *)stream->video_driver->node;
if (node->plugin_class) {
@@ -180,11 +184,11 @@ static inline int dxr3_present(xine_stream_t *stream)
static inline int dxr3_mvcommand(int fd_control, int command)
{
em8300_register_t reg;
-
+
reg.microcode_register = 1;
reg.reg = 0;
reg.val = command;
-
+
return ioctl(fd_control, EM8300_IOCTL_WRITEREG, &reg);
}
@@ -192,19 +196,19 @@ static inline int dxr3_mvcommand(int fd_control, int command)
static void *dxr3_init_plugin(xine_t *xine, void *data)
{
dxr3_decoder_class_t *this;
-
- this = (dxr3_decoder_class_t *)xine_xmalloc(sizeof (dxr3_decoder_class_t));
+
+ this = calloc(1, sizeof (dxr3_decoder_class_t));
if (!this) return NULL;
-
+
this->video_decoder_class.open_plugin = dxr3_open_plugin;
this->video_decoder_class.get_identifier = dxr3_get_identifier;
this->video_decoder_class.get_description = dxr3_get_description;
this->video_decoder_class.dispose = dxr3_class_dispose;
-
+
this->instance = 0;
-
+
this->clock = xine->clock;
-
+
return &this->video_decoder_class;
}
@@ -216,40 +220,40 @@ static video_decoder_t *dxr3_open_plugin(video_decoder_class_t *class_gen, xine_
dxr3_decoder_class_t *class = (dxr3_decoder_class_t *)class_gen;
config_values_t *cfg;
char tmpstr[128];
-
+
if (class->instance) return NULL;
if (!dxr3_present(stream)) return NULL;
-
- this = (dxr3_decoder_t *)xine_xmalloc(sizeof (dxr3_decoder_t));
+
+ this = calloc(1, sizeof (dxr3_decoder_t));
if (!this) return NULL;
-
+
cfg = stream->xine->config;
-
+
this->video_decoder.decode_data = dxr3_decode_data;
this->video_decoder.reset = dxr3_reset;
this->video_decoder.discontinuity = dxr3_discontinuity;
this->video_decoder.flush = dxr3_flush;
this->video_decoder.dispose = dxr3_dispose;
-
+
this->class = class;
this->stream = stream;
this->scr = NULL;
-
+
this->devnum = cfg->register_num(cfg, CONF_KEY, 0, CONF_NAME, CONF_HELP, 10, NULL, NULL);
-
+
snprintf(tmpstr, sizeof(tmpstr), "/dev/em8300-%d", this->devnum);
llprintf(LOG_VID, "Entering video init, devname=%s.\n",tmpstr);
-
+
/* open later, because dxr3_video_out might have it open until we request a frame */
this->fd_video = -1;
-
+
if ((this->fd_control = open(tmpstr, O_WRONLY)) < 0) {
- xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
_("dxr3_decode_video: Failed to open control device %s (%s)\n"), tmpstr, strerror(errno));
free(this);
return NULL;
}
-
+
this->use_panscan = cfg->register_enum(cfg,
"dxr3.use_panscan", 0, panscan_types, _("use Pan & Scan info"),
_("\"Pan & Scan\" is a special display mode which is sometimes used in MPEG "
@@ -262,14 +266,14 @@ static video_decoder_t *dxr3_open_plugin(video_decoder_class_t *class_gen, xine_
"Enable Pan & Scan based on information embedded in DVB streams. This makes "
"use of the Active Format Descriptor (AFD) used in some European DVB channels."),
10, dxr3_update_panscan, this);
-
+
this->dts_offset[0] = 21600;
this->dts_offset[1] = 21600;
this->dts_offset[2] = 21600;
-
+
this->force_duration_window = -FORCE_DURATION_WINDOW_SIZE;
this->last_vpts = this->class->clock->get_current_time(this->class->clock);
-
+
this->sync_every_frame = cfg->register_bool(cfg,
"dxr3.playback.sync_every_frame", 0, _("try to sync video every frame"),
_("Tries to set a synchronization timestamp for every frame. "
@@ -288,14 +292,14 @@ static video_decoder_t *dxr3_open_plugin(video_decoder_class_t *class_gen, xine_
"correction for NTSC streams erroneously labeled as PAL "
"streams is implemented. Enable only, when you encounter such streams."),
0, dxr3_update_correct_durations, this);
-
+
/* the dxr3 needs a longer prebuffering to have time for its internal decoding */
this->stream->metronom->set_option(this->stream->metronom, METRONOM_PREBUFFER, 90000);
-
+
(stream->video_out->open) (stream->video_out, stream);
-
+
class->instance = 1;
-
+
return &this->video_decoder;
}
@@ -313,7 +317,7 @@ static void dxr3_class_dispose(video_decoder_class_t *class_gen)
{
free(class_gen);
}
-
+
static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
{
@@ -324,9 +328,9 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
vo_frame_t *img;
uint8_t *buffer, byte;
uint32_t shift;
-
+
vpts = 0;
-
+
/* handle aspect hints from xine-dvdnav */
if (buf->decoder_flags & BUF_FLAG_SPECIAL) {
if (buf->decoder_info[1] == BUF_SPECIAL_ASPECT) {
@@ -338,12 +342,12 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
this->force_pan_scan = 0;
frame_format_change(this);
-
+
this->last_aspect_code = this->aspect_code;
}
return;
}
-
+
/* parse frames in the buffer handed in, evaluate headers,
* send frames to video_out and handle some syncing
*/
@@ -357,7 +361,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
}
/* header code of some kind found */
shift = 0xffffff00;
-
+
if (byte == 0xb2) {
/* check for AFD data */
if (buffer + 5 < buf->content + buf->size) {
@@ -446,7 +450,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
continue;
if (buf->decoder_flags & BUF_FLAG_PREVIEW)
continue;
-
+
/* pretend like we have decoded a frame */
img = this->stream->video_out->get_frame(this->stream->video_out,
this->width, this->height, this->ratio,
@@ -454,20 +458,20 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
img->pts = buf->pts;
img->bad_frame = 0;
img->duration = get_duration(this);
-
+
skip = img->draw(img, this->stream);
-
+
if (skip <= 0) { /* don't skip */
vpts = img->vpts; /* copy so we can free img */
-
+
if (this->correct_durations) {
/* calculate an average frame duration from metronom's vpts values */
this->avg_duration = this->avg_duration * 0.9 + (vpts - this->last_vpts) * 0.1;
llprintf(LOG_PTS, "average frame duration %d\n", this->avg_duration);
}
-
+
if (this->skip_count) this->skip_count--;
-
+
if (this->resync_window == 0 && this->scr && this->enhanced_mode &&
!this->scr->scanning) {
/* we are in sync, so we can lock the stream now */
@@ -484,7 +488,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
llprintf(LOG_VID, "%d frames to skip\n", skip);
vpts = 0;
this->avg_duration = 0;
-
+
/* handle frame skip conditions */
if (this->scr && !this->scr->scanning) this->skip_count += skip;
if (this->skip_count > SKIP_TOLERANCE) {
@@ -496,7 +500,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
this->skip_count = 0;
this->resync_window = 0;
}
-
+
if (this->scr && this->scr->scanning) this->resync_window = 0;
if (this->resync_window == 0 && this->scr && this->enhanced_mode &&
!this->scr->scanning) {
@@ -515,7 +519,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
img->free(img);
/* if sync_every_frame was disabled, decrease the counter
- * for a retry
+ * for a retry
* (it might be due to crappy studio logos and stuff
* so we should give the main movie a chance)
*/
@@ -527,7 +531,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
}
}
if (buf->decoder_flags & BUF_FLAG_PREVIEW) return;
-
+
/* ensure video device is open
* (we open it late because on occasion the dxr3 video out driver
* wants to open it)
@@ -537,15 +541,15 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
metronom_clock_t *clock = this->class->clock;
char tmpstr[128];
int64_t time;
-
+
/* open the device for the decoder */
snprintf (tmpstr, sizeof(tmpstr), "/dev/em8300_mv-%d", this->devnum);
if ((this->fd_video = open(tmpstr, O_WRONLY)) < 0) {
- xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
- _("dxr3_decode_video: Failed to open video device %s (%s)\n"), tmpstr, strerror(errno));
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ _("dxr3_decode_video: Failed to open video device %s (%s)\n"), tmpstr, strerror(errno));
return;
}
-
+
/* We may want to issue a SETPTS, so make sure the scr plugin
* is running and registered. Unfortuantely wa cannot do this
* earlier, because the dxr3's internal scr gets confused
@@ -558,11 +562,11 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
this->scr->scr_plugin.start(&this->scr->scr_plugin, time);
clock->register_scr(clock, &this->scr->scr_plugin);
}
-
+
/* update the pts timestamp in the card, which tags the data we write to it */
if (vpts) {
int64_t delay;
-
+
/* The PTS values written to the DXR3 must be modified based on the difference
* between stream's PTS and DTS (decoder timestamp). We receive this
* difference via decoder_info */
@@ -578,7 +582,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
llprintf(LOG_PTS, "PTS to DTS correction: %d\n", this->dts_offset[1]);
}
vpts -= this->dts_offset[2];
-
+
delay = vpts - this->class->clock->get_current_time(
this->class->clock);
llprintf(LOG_PTS, "SETPTS got %" PRId64 "\n", vpts);
@@ -592,7 +596,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
"dxr3_decode_video: set video pts failed (%s)\n", strerror(errno));
}
-
+
if (delay >= 90000) /* frame more than 1 sec ahead */
xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
"dxr3_decode_video: WARNING: vpts %" PRId64 " is %.02f seconds ahead of time!\n",
@@ -602,7 +606,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
}
else if (buf->pts)
llprintf(LOG_PTS, "skip buf->pts = %" PRId64 " (no vpts)\n", buf->pts);
-
+
/* now write the content to the dxr3 mpeg device and, in a dramatic
* break with open source tradition, check the return value
*/
@@ -613,7 +617,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
_("dxr3_decode_video: write to device would block. flushing\n"));
dxr3_flush(this_gen);
} else {
- xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
_("dxr3_decode_video: video device write failed (%s)\n"), strerror(errno));
}
return;
@@ -626,7 +630,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
static void dxr3_reset(video_decoder_t *this_gen)
{
dxr3_decoder_t *this = (dxr3_decoder_t *)this_gen;
-
+
this->sequence_open = 0;
}
@@ -634,10 +638,10 @@ static void dxr3_discontinuity(video_decoder_t *this_gen)
{
}
-static void dxr3_flush(video_decoder_t *this_gen)
+static void dxr3_flush(video_decoder_t *this_gen)
{
dxr3_decoder_t *this = (dxr3_decoder_t *)this_gen;
-
+
if (this->sequence_open && ++this->sequence_open > 5 &&
_x_stream_info_get(this->stream, XINE_STREAM_INFO_VIDEO_HAS_STILL)) {
/* The dxr3 needs a sequence end code for still menus to work correctly
@@ -655,18 +659,18 @@ static void dxr3_dispose(video_decoder_t *this_gen)
{
dxr3_decoder_t *this = (dxr3_decoder_t *)this_gen;
metronom_clock_t *clock = this->class->clock;
-
+
if (this->scr)
clock->unregister_scr(clock, &this->scr->scr_plugin);
-
+
dxr3_mvcommand(this->fd_control, MVCOMMAND_FLUSHBUF);
-
+
if (this->fd_video >= 0) close(this->fd_video);
close(this->fd_control);
-
+
this->stream->video_out->close(this->stream->video_out, this->stream);
this->class->instance = 0;
-
+
free(this);
}
@@ -680,11 +684,11 @@ static void parse_mpeg_header(dxr3_decoder_t *this, uint8_t * buffer)
this->width = ((this->height >> 12) + 15) & ~15;
this->height = ((this->height & 0xfff) + 15) & ~15;
this->aspect_code = buffer[3] >> 4;
-
+
this->have_header_info = 1;
-
+
if (this->force_aspect) this->aspect_code = this->force_aspect;
-
+
/* when width, height or aspect changes,
* we have to send an event for dxr3 spu decoder */
if (!this->last_width || !this->last_height || !this->last_aspect_code ||
@@ -701,7 +705,7 @@ static void parse_mpeg_header(dxr3_decoder_t *this, uint8_t * buffer)
static int get_duration(dxr3_decoder_t *this)
{
int duration;
-
+
switch (this->frame_rate_code) {
case 1: /* 23.976 */
duration = 3754; /* actually it's 3753.75 */
@@ -728,19 +732,19 @@ static int get_duration(dxr3_decoder_t *this)
duration = 1500;
break;
default:
- xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
+ xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
_("dxr3_decode_video: WARNING: unknown frame rate code %d\n"), this->frame_rate_code);
duration = 0;
break;
}
-
+
/* update stream metadata */
_x_stream_info_set(this->stream, XINE_STREAM_INFO_FRAME_DURATION, duration);
-
+
if (this->correct_durations && duration) {
/* we set an initial average frame duration here */
if (!this->avg_duration) this->avg_duration = duration;
-
+
/* Apply a correction to the framerate-code if metronom
* insists on a different frame duration.
* The code below is for NTCS streams labeled as PAL streams.
@@ -765,7 +769,7 @@ static int get_duration(dxr3_decoder_t *this)
return 3000;
}
}
-
+
if (this->force_duration_window == -FORCE_DURATION_WINDOW_SIZE)
/* we are far from a force_duration window */
return duration;
@@ -778,7 +782,7 @@ static int get_duration(dxr3_decoder_t *this)
this->force_duration_window = -FORCE_DURATION_WINDOW_SIZE;
}
}
-
+
return duration;
}
@@ -797,7 +801,7 @@ static void frame_format_change(dxr3_decoder_t *this)
data.aspect = this->aspect_code;
data.pan_scan = this->force_pan_scan;
xine_event_send(this->stream, &event);
-
+
/* update ratio */
switch (this->aspect_code) {
case 2:
@@ -813,12 +817,12 @@ static void frame_format_change(dxr3_decoder_t *this)
if (this->have_header_info)
this->ratio = (double)this->width / (double)this->height;
}
-
+
/* update stream metadata */
_x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_WIDTH, this->width);
_x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_HEIGHT, this->height);
_x_stream_info_set(this->stream, XINE_STREAM_INFO_VIDEO_RATIO, 10000 * this->ratio);
-
+
_x_meta_info_set_utf8(this->stream, XINE_META_INFO_VIDEOCODEC, "MPEG (DXR3)");
}