Index: xine_input_vdr.c
===================================================================
RCS file: /cvsroot/xineliboutput/vdr-xineliboutput/xine_input_vdr.c,v
retrieving revision 1.82
retrieving revision 1.84
diff -u -r1.82 -r1.84
--- xine_input_vdr.c	17 May 2007 17:36:26 -0000	1.82
+++ xine_input_vdr.c	30 May 2007 08:13:24 -0000	1.84
@@ -4,7 +4,7 @@
  * See the main source file 'xineliboutput.c' for copyright information and
  * how to reach the author.
  *
- * $Id: xine_input_vdr.c,v 1.82 2007/05/17 17:36:26 phintuka Exp $
+ * $Id: xine_input_vdr.c,v 1.84 2007/05/30 08:13:24 phintuka Exp $
  *
  */
 
@@ -58,6 +58,12 @@
 
 /***************************** DEFINES *********************************/
 
+/* Support for ffmpeg mpeg2 decoder. 
+   Priority must be increased in $HOME/.xine/config_xineliboutput:
+       engine.decoder_priorities.ffmpegvideo:1
+*/
+#define FFMPEG_DEC
+
 /*#define LOG_UDP*/
 /*#define LOG_OSD*/
 /*#define LOG_CMD*/
@@ -244,6 +250,7 @@
   int                 audio_stream_id; /* ((PES PID) << 8) | (SUBSTREAM ID) */
   int                 prev_audio_stream_id;
   int                 sw_volume_control;
+  int                 ffmpeg_video_decoder;
 
   /* SCR */
   pvrscr_t           *scr;
@@ -894,11 +901,16 @@
 static void pes_strip_pts(uint8_t *buf, int size)
 {
   if(size > 13 && buf[7] & 0x80) { /* pts avail */
+    int pes_len = (buf[4] << 8) | buf[5];
     if ((buf[6] & 0xC0) != 0x80)
       return;
     if ((buf[6] & 0x30) != 0)
       return;
-    buf[7] &= ~0x80; /* clear pts flag */
+    pes_len -= 5;     /* update packet len */
+    buf[4]   = pes_len >> 8;   /* packet len (hi) */
+    buf[5]   = pes_len & 0xff; /* packet len (lo) */
+    buf[7]  &= 0x7f;  /* clear pts flag */
+    buf[8]  -= 5;     /* update header len */
     memmove(buf+9, buf+14, size-14);
   }
 }
@@ -1416,6 +1428,7 @@
     buf->content = buf->mem;
     buf->size = 0;
     buf->type = BUF_DEMUX_BLOCK;
+    buf->pts  = 0;
 
     buf->free_buffer = buffer_pool_free;
   }
@@ -4688,7 +4701,7 @@
 #  include "cache_iframe.c"
 #endif
 
-static void update_frames(vdr_input_plugin_t *this, uint8_t *data, int len)
+static int update_frames(vdr_input_plugin_t *this, uint8_t *data, int len)
 {
   int Length = len;
   int i = 8;
@@ -4698,14 +4711,17 @@
   i += data[i] + 1;   /* possible additional header bytes */
   for (; i < Length-5; i++) {
     if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 && data[i + 3] == 0) {
-      switch ((data[i + 5] >> 3) & 0x07) {
+      uint8_t type = ((data[i + 5] >> 3) & 0x07);
+      switch (type) {
         case 1: this->I_frames++; LOGSCR("I"); break;
         case 2: this->P_frames++; LOGSCR("P"); break;
         case 3: this->B_frames++; LOGSCR("B"); break;
-        default: return;
+        default: return 0;
       }
+      return type;
     }
   }
+  return 0;
 }
 
 static buf_element_t *vdr_plugin_read_block (input_plugin_t *this_gen,
@@ -4940,9 +4956,30 @@
     }
   }
 
-  if(this->live_mode && this->I_frames < 4 && 
-     buf->content[3] == 0xe0 && buf->size > 32)
-    update_frames(this, buf->content, buf->size);
+#ifndef FFMPEG_DEC
+  if(this->live_mode && this->I_frames < 4)
+    if(buf->content[3] == 0xe0 && buf->size > 32)
+      update_frames(this, buf->content, buf->size);
+#else /* FFMPEG_DEC */
+  if(this->ffmpeg_video_decoder || (this->live_mode && this->I_frames < 4))
+    if(buf->content[3] == 0xe0 && buf->size > 32) {
+      int type = update_frames(this, buf->content, buf->size);
+      if(type && this->ffmpeg_video_decoder) {
+	buf_element_t *cbuf = get_buf_element(this, 0, 1);
+	/* signal FRAME_END to decoder */
+	if(cbuf) {
+	  cbuf->type = BUF_VIDEO_MPEG;
+	  cbuf->decoder_flags = BUF_FLAG_FRAME_END;
+	  this->stream->video_fifo->put (this->stream->video_fifo, cbuf);
+	}
+	/* for some reason ffmpeg mpeg2 decoder does not understand pts'es in B frames ? 
+	 * (B-frame pts's are smaller than in previous P-frame) 
+	 * Anyway, without this block of code B frames with pts are dropped. */
+	if(type == 3 && pts_from_pes(buf->content, buf->size) > INT64_C(0))
+	  pes_strip_pts(buf->content, buf->size);
+      }
+    }
+#endif
 
   TRACE("vdr_plugin_read_block: return data, pos end = %" PRIu64, this->curpos);
   return buf;
@@ -5925,6 +5962,7 @@
   this->still_mode   = 0;
   this->stream_start = 1;
   this->send_pts     = 0;
+  this->ffmpeg_video_decoder = -1;
 
   this->rescale_osd  = 0;
   this->unscaled_osd = 0;
@@ -5997,6 +6035,23 @@
 
   this->udp_data = NULL;
 
+#ifdef FFMPEG_DEC
+  if(this->ffmpeg_video_decoder < 0) {
+    xine_cfg_entry_t ffmpegprio, mpeg2prio;
+    this->ffmpeg_video_decoder = 0;
+    if (xine_config_lookup_entry(this->stream->xine, "engine.decoder_priorities.ffmpegvideo", &ffmpegprio)) {
+      LOGMSG("ffmpeg video decoder priority: %d", ffmpegprio.num_value);
+      this->ffmpeg_video_decoder = 1;
+      if (xine_config_lookup_entry(this->stream->xine, "engine.decoder_priorities.mpeg2", &mpeg2prio)) {
+	LOGMSG("libmpeg2 video decoder priority: %d", mpeg2prio.num_value);
+	if (mpeg2prio.num_value > ffmpegprio.num_value)
+	  this->ffmpeg_video_decoder = 0;
+      }
+      LOGMSG(" --> using %s mpeg2 video decoder", this->ffmpeg_video_decoder?"ffmpeg":"libmpeg2");
+    }
+  }
+#endif
+
   LOGDBG("vdr_class_get_instance done.");
   return &this->input_plugin;
 }
