static void
dxr3audiosink_chain_ac3 (GstPad * pad, GstData * _data)
{
  Dxr3AudioSink *sink;
  gint bytes_written = 0;
  GstBuffer *buf;

  g_return_if_fail (pad != NULL);
  g_return_if_fail (GST_IS_PAD (pad));
  g_return_if_fail (_data != NULL);

  sink = DXR3AUDIOSINK (gst_pad_get_parent (pad));

  if (GST_IS_EVENT (_data)) {
    dxr3audiosink_handle_event (pad, GST_EVENT (_data));
    return;
  }

  buf = GST_BUFFER (_data);

  if (sink->mode != DXR3AUDIOSINK_MODE_AC3) {
    /* Switch to AC3 mode. */
    dxr3audiosink_set_mode_ac3 (sink);
  }

  if (GST_OBJECT_FLAG_IS_SET (sink, DXR3AUDIOSINK_OPEN)) {
    int event;

    if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
      /* We have a new scr value. */

/*       fprintf (stderr, "------ Audio Time %.04f\n", */
/*                (double) GST_BUFFER_TIMESTAMP (buf) / GST_SECOND); */

      sink->scr = GSTTIME_TO_MPEGTIME (GST_BUFFER_TIMESTAMP (buf));
    }

    /* Push the new data into the padder. */
    ac3p_push_data (sink->padder, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));

    /* Parse the data. */
    event = ac3p_parse (sink->padder);
    while (event != AC3P_EVENT_PUSH) {
      switch (event) {
        case AC3P_EVENT_FRAME:
          /* We have a new frame: */

          /* Update the system reference clock (SCR) in the card. */
        {
          unsigned in, out, odelay;
          unsigned diff;

          ioctl (sink->control_fd, EM8300_IOCTL_SCR_GET, &out);

          ioctl (sink->audio_fd, SNDCTL_DSP_GETODELAY, &odelay);
          /* 192000 bytes/sec */

          in = MPEGTIME_TO_DXRTIME (sink->scr - (odelay * 90) / 192);
          diff = in > out ? in - out : out - in;
          if (diff > 1800) {
            dxr3audiosink_set_scr (sink, in);
          }
        }

          /* Update our SCR value. */
          sink->scr += TIME_FOR_BYTES (ac3p_frame_size (sink->padder));

          /* Write the frame to the sound device. */
          bytes_written = write (sink->audio_fd, ac3p_frame (sink->padder),
              AC3P_IEC_FRAME_SIZE);

          if (bytes_written < AC3P_IEC_FRAME_SIZE) {
            fprintf (stderr, "dxr3audiosink: Warning: %d bytes should be "
                "written, only %d bytes written\n",
                AC3P_IEC_FRAME_SIZE, bytes_written);
          }

          break;
      }

      event = ac3p_parse (sink->padder);
    }
  }

  gst_buffer_unref (buf);
}
static gboolean
dxr3videosink_handle_event (GstPad * pad, GstEvent * event)
{
  GstEventType type;
  Dxr3VideoSink *sink;

  sink = DXR3VIDEOSINK (gst_pad_get_parent (pad));

  type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;

  switch (type) {
    case GST_EVENT_EMPTY:
      //fprintf (stderr, "++++++ Video empty event\n");
    {
      /* FIXME: Handle this with a discontinuity or something. */
      /* Write an MPEG2 sequence end code, to ensure that the card
         actually displays the last picture.  Apparently some DVDs are
         encoded without proper sequence end codes. */
      static const guint8 sec[4] = { 0x00, 0x00, 0x01, 0xb7 };

      if (sink->cur_buf != NULL) {
        dxr3videosink_write_data (sink, 0);
      }

      write (sink->video_fd, &sec, 4);
    }
      break;

    case GST_EVENT_DISCONTINUOUS:
      //fprintf (stderr, "++++++ Video discont event\n");
    {
      gint64 time;
      gboolean has_time;
      unsigned cur_scr, mpeg_scr, diff;

      has_time = gst_event_discont_get_value (event, GST_FORMAT_TIME, &time);
      if (has_time) {
/*         fprintf (stderr, "^^^^^^ Discontinuous event has time %.4f\n", */
/*                  (double) time / GST_SECOND); */

        /* If the SCR in the card is way off, fix it. */
        ioctl (sink->control_fd, EM8300_IOCTL_SCR_GET, &cur_scr);
        mpeg_scr = MPEGTIME_TO_DXRTIME (GSTTIME_TO_MPEGTIME (time));

        diff = cur_scr > mpeg_scr ? cur_scr - mpeg_scr : mpeg_scr - cur_scr;
        if (diff > 1800) {
          unsigned zero = 0;

/*           fprintf (stderr, "====== Adjusting SCR from video\n"); */

          ioctl (sink->control_fd, EM8300_IOCTL_SCR_SET, &zero);
          ioctl (sink->control_fd, EM8300_IOCTL_SCR_SET, &mpeg_scr);
        }
      } else {
/*         fprintf (stderr, "^^^^^^ Discontinuous event has no time\n"); */
      }
    }
      break;

    case GST_EVENT_FLUSH:
      dxr3videosink_reset_parser (sink);
      break;

    default:
      gst_pad_event_default (pad, event);
      break;
  }

  return TRUE;
}
static void
dxr3audiosink_chain_pcm (GstPad * pad, GstData * _data)
{
  Dxr3AudioSink *sink;
  gint bytes_written = 0;
  GstBuffer *buf;

  g_return_if_fail (pad != NULL);
  g_return_if_fail (GST_IS_PAD (pad));
  g_return_if_fail (_data != NULL);

  sink = DXR3AUDIOSINK (gst_pad_get_parent (pad));

  if (GST_IS_EVENT (_data)) {
    dxr3audiosink_handle_event (pad, GST_EVENT (_data));
    return;
  }

  buf = GST_BUFFER (_data);

  if (sink->mode != DXR3AUDIOSINK_MODE_PCM) {
    /* Switch to PCM mode. */
    dxr3audiosink_set_mode_pcm (sink);
  }

  if (GST_OBJECT_FLAG_IS_SET (sink, DXR3AUDIOSINK_OPEN)) {
    if (GST_BUFFER_TIMESTAMP (buf) != GST_CLOCK_TIME_NONE) {
      /* We have a new scr value. */
      sink->scr = GSTTIME_TO_MPEGTIME (GST_BUFFER_TIMESTAMP (buf));
    }

    /* Update the system reference clock (SCR) in the card. */
    {
      unsigned in, out, odelay;
      unsigned diff;

      ioctl (sink->control_fd, EM8300_IOCTL_SCR_GET, &out);

      ioctl (sink->audio_fd, SNDCTL_DSP_GETODELAY, &odelay);

      in = MPEGTIME_TO_DXRTIME (sink->scr - (odelay * 90) / 192);
      diff = in > out ? in - out : out - in;
      if (diff > 1800) {
        dxr3audiosink_set_scr (sink, in);
      }
    }

    /* Update our SCR value. */
    sink->scr += (unsigned) (GST_BUFFER_SIZE (buf) *
        (90000.0 / ((float) sink->rate * 4)));

    /* Write the buffer to the sound device. */
    bytes_written = write (sink->audio_fd, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf));
    if (bytes_written < GST_BUFFER_SIZE (buf)) {
      fprintf (stderr, "dxr3audiosink: Warning: %d bytes should be "
          "written, only %d bytes written\n",
          GST_BUFFER_SIZE (buf), bytes_written);
    }
  }

  gst_buffer_unref (buf);
}