summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dxr3/dxr3_decode_video.c234
1 files changed, 134 insertions, 100 deletions
diff --git a/src/dxr3/dxr3_decode_video.c b/src/dxr3/dxr3_decode_video.c
index dbd510020..ccb15e0f0 100644
--- a/src/dxr3/dxr3_decode_video.c
+++ b/src/dxr3/dxr3_decode_video.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: dxr3_decode_video.c,v 1.53 2004/04/10 15:29:57 mroi Exp $
+ * $Id: dxr3_decode_video.c,v 1.54 2004/04/17 14:18:14 mroi Exp $
*/
/* dxr3 video decoder plugin.
@@ -43,8 +43,12 @@
#define LOG_VID 0
#define LOG_PTS 0
+/* once activated, we wait for this amount of missing pan&scan info
+ * before disabling it again */
+#define PAN_SCAN_WINDOW_SIZE 50
+
/* the number of frames to pass after an out-of-sync situation
- before locking the stream again */
+ * before locking the stream again */
#define RESYNC_WINDOW_SIZE 50
/* we adjust vpts_offset in metronom, when skip_count reaches this value */
@@ -117,6 +121,11 @@ typedef struct dxr3_decoder_s {
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 */
@@ -139,8 +148,10 @@ static inline int dxr3_present(xine_stream_t *stream);
static inline int dxr3_mvcommand(int fd_control, int command);
static inline void parse_mpeg_header(dxr3_decoder_t *this, uint8_t *buffer);
static inline int get_duration(dxr3_decoder_t *this);
+static void frame_format_change(dxr3_decoder_t *this);
/* config callbacks */
+static void dxr3_update_panscan(void *this_gen, xine_cfg_entry_t *entry);
static void dxr3_update_sync_mode(void *this_gen, xine_cfg_entry_t *entry);
static void dxr3_update_enhanced_mode(void *this_gen, xine_cfg_entry_t *entry);
static void dxr3_update_correct_durations(void *this_gen, xine_cfg_entry_t *entry);
@@ -168,6 +179,7 @@ static void *dxr3_init_plugin(xine_t *xine, void *data)
static video_decoder_t *dxr3_open_plugin(video_decoder_class_t *class_gen, xine_stream_t *stream)
{
+ static char *panscan_types[] = { "only when forced", "use MPEG hint", "use DVB hint", NULL };
dxr3_decoder_t *this;
dxr3_decoder_class_t *class = (dxr3_decoder_class_t *)class_gen;
config_values_t *cfg;
@@ -208,27 +220,25 @@ static video_decoder_t *dxr3_open_plugin(video_decoder_class_t *class_gen, xine_
return NULL;
}
- this->have_header_info = 0;
- this->sequence_open = 0;
- this->repeat_first_field = 0;
-
- this->force_aspect = 0;
- this->force_pan_scan = 0;
-
- this->last_width = 0;
- this->last_height = 0;
- this->last_aspect_code = 0;
+ 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 "
+ "encoded material. You can specify here, how to handle such content.\n\n"
+ "only when forced\n"
+ "Use Pan & Scan only, when the content you are playing enforces it.\n\n"
+ "use MPEG hint\n"
+ "Enable Pan & Scan based on information embedded in the MPEG video stream.\n\n"
+ "use DVB hint\n"
+ "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->sync_retry = 0;
- this->resync_window = 0;
- this->skip_count = 0;
this->force_duration_window = -FORCE_DURATION_WINDOW_SIZE;
this->last_vpts = this->class->clock->get_current_time(this->class->clock);
- this->avg_duration = 0;
this->sync_every_frame = cfg->register_bool(cfg,
"dxr3.sync_every_frame", 0, _("try to sync video every frame"),
@@ -290,9 +300,6 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
/* handle aspect hints from xine-dvdnav */
if (buf->decoder_flags & BUF_FLAG_SPECIAL) {
if (buf->decoder_info[1] == BUF_SPECIAL_ASPECT) {
- xine_event_t event;
- xine_format_change_data_t data;
-
this->aspect_code = this->force_aspect = buf->decoder_info[2];
if (buf->decoder_info[3] == 0x1 && this->force_aspect == 3)
/* letterboxing is denied, we have to do pan&scan */
@@ -300,32 +307,7 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
else
this->force_pan_scan = 0;
- /* send an event for dxr3 spu decoder */
- event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
- event.stream = this->stream;
- event.data = &data;
- event.data_length = sizeof(data);
- data.width = this->last_width;
- data.height = this->last_height;
- data.aspect = this->force_aspect;
- data.pan_scan = this->force_pan_scan;
- xine_event_send(this->stream, &event);
-
- /* update ratio */
- switch (this->aspect_code) {
- case 2:
- this->ratio = 4.0 / 3.0;
- break;
- case 3:
- this->ratio = 16.0 / 9.0;
- break;
- case 4:
- this->ratio = 2.11;
- break;
- default:
- if (this->have_header_info)
- this->ratio = (double)this->last_width / (double)this->last_height;
- }
+ frame_format_change(this);
this->last_aspect_code = this->aspect_code;
}
@@ -345,6 +327,19 @@ 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) {
+ if (buffer[0] == 0x44 && buffer[1] == 0x54 && buffer[2] == 0x47) {
+ this->afd_code = buffer[5] & 0x0f;
+ if (this->aspect_code == 3)
+ /* 4:3 image in 16:9 frame -> zoomit! */
+ this->afd_smart_change = PAN_SCAN_WINDOW_SIZE;
+ }
+ }
+ continue;
+ }
if (byte == 0xb3) {
/* sequence data */
if (buffer + 3 < buf->content + buf->size)
@@ -354,16 +349,33 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
}
if (byte == 0xb5) {
/* extension data */
- if (buffer + 3 < buf->content + buf->size)
- if ((buffer[0] & 0xf0) == 0x80)
+ /* parse the extension type and use what is necessary...
+ * types are: sequence(1), sequence_display(2), quant_matrix(3),
+ * copyright(4), picture_display(7), picture_coding(8), ... */
+ if (buffer + 4 < buf->content + buf->size) {
+ switch (buffer[0] >> 4) {
+ case 2:
+ case 7:
+ /* picture_display and sequence_display are pan&scan info */
+ if (this->use_panscan) this->panscan_smart_change = PAN_SCAN_WINDOW_SIZE;
+ break;
+ case 8:
this->repeat_first_field = (buffer[3] >> 1) & 1;
-#if 0
- /* this disables frame jitter in progressive content, but
- * unfortunately it makes the card drop one field on stills */
- if (buffer + 4 < buf->content + buf->size)
- if ((buffer[0] & 0xf0) == 0x80)
- buffer[4] &= ~(1 << 7);
+#if 0 /* TODO: this needs more testing */
+ /* clearing the progessive flag gets rid of the frame jitter with
+ * TV-out in the lower third of the image; but we have to set this
+ * flag, when a still frame is coming along, otherwise the card will
+ * drop one of the fields; therefore we check for the fifo size */
+ if (!((dxr3_driver_t *)this->stream->video_driver)->overlay_enabled) {
+ if (this->stream->video_fifo->fifo_size > this->stream->video_fifo->buffer_pool_capacity / 2)
+ buffer[4] &= ~(1 << 7);
+ else
+ buffer[4] |= (1 << 7);
+ }
#endif
+ break;
+ }
+ }
/* check if we can keep syncing */
if (this->repeat_first_field && this->sync_retry) /* reset counter */
this->sync_retry = 500;
@@ -375,6 +387,28 @@ static void dxr3_decode_data(video_decoder_t *this_gen, buf_element_t *buf)
this->sync_every_frame = 0;
this->sync_retry = 500; /* see you later */
}
+ /* check for pan&scan state */
+ if (this->use_panscan && (this->panscan_smart_change > 0 || this->afd_smart_change > 0)) {
+ this->panscan_smart_change--;
+ this->afd_smart_change--;
+ if (this->panscan_smart_change > 0 || this->afd_smart_change > 0) {
+ /* only pan&scan if source is anamorphic */
+ if (this->aspect_code == 3) {
+ if (this->afd_smart_change && this->use_panscan == 2 && this->afd_code == 9)
+ this->force_pan_scan = 1; /* panscan info available -> zoom */
+ else if (this->afd_smart_change && this->use_panscan == 2 && this->afd_code != 9)
+ this->force_pan_scan = 0; /* force no panscan - image is 16:9 */
+ else if (this->use_panscan == 1 && this->panscan_smart_change)
+ this->force_pan_scan = 1; /* panscan info available, ignore AFD mode */
+ else if (!this->afd_smart_change && this->panscan_smart_change)
+ this->force_pan_scan = 1;
+ frame_format_change(this);
+ }
+ } else {
+ this->force_pan_scan = 0;
+ frame_format_change(this);
+ }
+ }
continue;
}
if (byte == 0xb7)
@@ -680,38 +714,7 @@ static inline void parse_mpeg_header(dxr3_decoder_t *this, uint8_t * buffer)
(this->last_width != this->width) ||
(this->last_height != this->height) ||
(this->last_aspect_code != this->aspect_code)) {
- xine_event_t event;
- xine_format_change_data_t data;
- event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
- event.stream = this->stream;
- event.data = &data;
- event.data_length = sizeof(data);
- data.width = this->width;
- data.height = this->height;
- 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:
- this->ratio = 4.0 / 3.0;
- break;
- case 3:
- this->ratio = 16.0 / 9.0;
- break;
- case 4:
- this->ratio = 2.11;
- break;
- default:
- 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);
-
+ frame_format_change(this);
this->last_width = this->width;
this->last_height = this->height;
this->last_aspect_code = this->aspect_code;
@@ -802,29 +805,60 @@ static inline int get_duration(dxr3_decoder_t *this)
return duration;
}
-static void dxr3_update_sync_mode(void *this_gen, xine_cfg_entry_t *entry)
+static void frame_format_change(dxr3_decoder_t *this)
{
- dxr3_decoder_t *this = (dxr3_decoder_t *)this_gen;
+ /* inform the dxr3 SPU decoder about the current format,
+ * so that it can choose the correctly matching SPU */
+ xine_event_t event;
+ xine_format_change_data_t data;
+ event.type = XINE_EVENT_FRAME_FORMAT_CHANGE;
+ event.stream = this->stream;
+ event.data = &data;
+ event.data_length = sizeof(data);
+ data.width = this->width;
+ data.height = this->height;
+ 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:
+ this->ratio = 4.0 / 3.0;
+ break;
+ case 3:
+ this->ratio = 16.0 / 9.0;
+ break;
+ case 4:
+ this->ratio = 2.11;
+ break;
+ default:
+ if (this->have_header_info)
+ this->ratio = (double)this->width / (double)this->height;
+ }
- this->sync_every_frame = entry->num_value;
- xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
- "dxr3_decode_video: setting sync_every_frame to %s\n", (entry->num_value ? "on" : "off"));
+ /* 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);
}
-static void dxr3_update_enhanced_mode(void *this_gen, xine_cfg_entry_t *entry)
+static void dxr3_update_panscan(void *this_gen, xine_cfg_entry_t *entry)
{
- dxr3_decoder_t *this = (dxr3_decoder_t *)this_gen;
+ ((dxr3_decoder_t *)this_gen)->use_panscan = entry->num_value;
+}
- this->enhanced_mode = entry->num_value;
- xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
- "dxr3_decode_video: setting enhanced mode to %s\n", (entry->num_value ? "on" : "off"));
+static void dxr3_update_sync_mode(void *this_gen, xine_cfg_entry_t *entry)
+{
+ ((dxr3_decoder_t *)this_gen)->sync_every_frame = entry->num_value;
}
-static void dxr3_update_correct_durations(void *this_gen, xine_cfg_entry_t *entry)
+static void dxr3_update_enhanced_mode(void *this_gen, xine_cfg_entry_t *entry)
{
- dxr3_decoder_t *this = (dxr3_decoder_t *)this_gen;
+ ((dxr3_decoder_t *)this_gen)->enhanced_mode = entry->num_value;
+}
- this->correct_durations = entry->num_value;
- xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG,
- "dxr3_decode_video: setting correct_durations mode to %s\n", (entry->num_value ? "on" : "off"));
+static void dxr3_update_correct_durations(void *this_gen, xine_cfg_entry_t *entry)
+{
+ ((dxr3_decoder_t *)this_gen)->correct_durations = entry->num_value;
}