vdr/xine-lib-vdr/src/libffmpeg Makefile.am Makefile.in audio_decoder.c diff_to_ffmpeg_cvs.txt dvaudio_decoder.c mpeg_parser.c mpeg_parser.h video_decoder.c xine_decoder.c xine_decoder.h xine_encoder.c

Darren Salt pkg-vdr-dvb-changes@lists.alioth.debian.org
Mon, 04 Apr 2005 22:29:54 +0000


Update of /cvsroot/pkg-vdr-dvb/vdr/xine-lib-vdr/src/libffmpeg
In directory haydn:/tmp/cvs-serv2129/src/libffmpeg

Added Files:
	Makefile.am Makefile.in audio_decoder.c diff_to_ffmpeg_cvs.txt 
	dvaudio_decoder.c mpeg_parser.c mpeg_parser.h video_decoder.c 
	xine_decoder.c xine_decoder.h xine_encoder.c 
Log Message:
Import of VDR-patched xine-lib.

--- NEW FILE: mpeg_parser.c ---
/*
 * Copyright (C) 2001-2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 * Simple MPEG-ES parser/framer by Thibaut Mattern (tmattern@noos.fr)
 *   based on libmpeg2 decoder.
 *
 * $Id: mpeg_parser.c,v 1.1 2005/04/04 22:29:51 dsalt-guest Exp $
 */
#define LOG_MODULE "mpeg_parser"
#define LOG_VERBOSE
/*
#define LOG
*/
#include "mpeg_parser.h"

/* mpeg frame rate table from lavc */
static const int frame_rate_tab[][2] = {
    {    0,    0},
    {24000, 1001},
    {   24,    1},
    {   25,    1},
    {30000, 1001},
    {   30,    1},
    {   50,    1},
    {60000, 1001},
    {   60,    1},
  /* Xing's 15fps: (9) */
    {   15,    1},
  /* libmpeg3's "Unofficial economy rates": (10-13) */
    {    5,    1},
    {   10,    1},
    {   12,    1},
    {   15,    1},
    {    0,    0},
};

void mpeg_parser_init (mpeg_parser_t *parser)
{
  mpeg_parser_reset(parser);
}

void mpeg_parser_reset (mpeg_parser_t *parser)
{
  parser->shift                  = 0xffffff00;
  parser->is_sequence_needed     = 1;
  parser->in_slice               = 0;
  parser->chunk_ptr              = parser->chunk_buffer;
  parser->chunk_start            = parser->chunk_buffer;
  parser->buffer_size            = 0;
  parser->code                   = 0xb4;
  parser->picture_coding_type    = 0;
  parser->width                  = 0;
  parser->height                 = 0;
  parser->rate_code              = 0;
  parser->aspect_ratio_info      = 0;
  parser->frame_duration         = 0;
  parser->is_mpeg1               = 0;
  parser->has_sequence           = 0;
  parser->frame_aspect_ratio     = 0.0;
}

static void parse_header_picture (mpeg_parser_t *parser, uint8_t * buffer)
{
  parser->picture_coding_type = (buffer [1] >> 3) & 7;
}

static double get_aspect_ratio(mpeg_parser_t *parser)
{
  double ratio;
  double mpeg1_pel_ratio[16] = {1.0 /* forbidden */,
    1.0, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157,
    0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 1.0 /*reserved*/ };

  if( !parser->is_mpeg1 ) {
    /* these hardcoded values are defined on mpeg2 standard for
     * aspect ratio. other values are reserved or forbidden.  */
    switch (parser->aspect_ratio_info) {
    case 2:
      ratio = 4.0 / 3.0;
      break;
    case 3:
      ratio = 16.0 / 9.0;
      break;
    case 4:
      ratio = 2.11 / 1.0;
      break;
    case 1:
    default:
      ratio = (double)parser->width / (double)parser->height;
      break;
    }
  } else {
    /* mpeg1 constants refer to pixel aspect ratio */
    ratio = (double)parser->width / (double)parser->height;
    ratio /= mpeg1_pel_ratio[parser->aspect_ratio_info];
  }

  return ratio;
}

static int parse_chunk (mpeg_parser_t *parser, int code, uint8_t *buffer, int len)
{
  int is_frame_done;
  int next_code = parser->code;
  
  /* wait for sequence_header_code */
  if (parser->is_sequence_needed) {
    if (code != 0xb3) {
      lprintf("waiting for sequence header\n");
      parser->chunk_ptr = parser->chunk_buffer;
      return 0;
    }
  }
  
  is_frame_done = parser->in_slice && ((!next_code)  || (next_code == 0xb7));

  if (is_frame_done)
    parser->in_slice = 0;

  switch (code) {
  case 0x00:        /* picture_start_code */
    
    parse_header_picture (parser, buffer);

    parser->in_slice = 1;

    switch (parser->picture_coding_type) {
    case B_TYPE:
      lprintf ("B-Frame\n");
      break;
      
    case P_TYPE:
      lprintf ("P-Frame\n");
      break;
        
    case I_TYPE:
      lprintf ("I-Frame\n");
      break;
    }
    break;

  case 0xb2:     /* user data code */
    /* process_userdata(mpeg2dec, buffer); */
    break;

  case 0xb3:     /* sequence_header_code */
    {
      int value;
      int width;
      int height;
      
      if (parser->is_sequence_needed) {
        parser->is_sequence_needed = 0;
      }
      
      if ((buffer[6] & 0x20) != 0x20) {
        lprintf("Invalid sequence: missing marker_bit\n");
        parser->has_sequence = 0;
        break;  /* missing marker_bit */
      }

      value = (buffer[0] << 16) |
              (buffer[1] << 8)  |
               buffer[2];
      width  = ((value >> 12) + 15) & ~15;
      height = ((value & 0xfff) + 15) & ~15;
      
      if ((width > 1920) || (height > 1152)) {
        lprintf("Invalid sequence: width=%d, height=%d\n", width, height);
        parser->has_sequence = 0;
        break;  /* size restrictions for MP@HL */
      }

      parser->width  = width;
      parser->height = height;
      parser->rate_code = buffer[3] & 15;
      parser->aspect_ratio_info = buffer[3] >> 4;
      
      if (parser->rate_code < sizeof(frame_rate_tab)) {
        parser->frame_duration = 90000;
        parser->frame_duration *= frame_rate_tab[parser->rate_code][1];
        parser->frame_duration /= frame_rate_tab[parser->rate_code][0];
      } else {
        printf ("invalid/unknown frame rate code : %d \n",
                parser->rate_code);
        parser->frame_duration = 0;
      }

      parser->has_sequence = 1;
      parser->is_mpeg1 = 1;
    }
    break;
    
  case 0xb5:     /* extension_start_code */
    switch (buffer[0] & 0xf0) {
    case 0x10:     /* sequence extension */
      parser->is_mpeg1 = 0;
    }

  default:
    if (code >= 0xb9)
      lprintf ("stream not demultiplexed ?\n");

    if (code >= 0xb0)
      break;
  }
  return is_frame_done;
}

static inline uint8_t *copy_chunk (mpeg_parser_t *parser,
                                   uint8_t *current, uint8_t *end)
{
  uint32_t shift;
  uint8_t *chunk_ptr;
  uint8_t *limit;
  uint8_t byte;

  shift = parser->shift;
  chunk_ptr = parser->chunk_ptr;

  limit = current + (parser->chunk_buffer + BUFFER_SIZE - chunk_ptr);
  if (limit > end)
    limit = end;

  while (1) {

    byte = *current++;
    *chunk_ptr++ = byte;
    if (shift != 0x00000100) {
      shift = (shift | byte) << 8;
      if (current < limit)
        continue;
      if (current == end) {
        parser->chunk_ptr = chunk_ptr;
        parser->shift = shift;
        lprintf("Need more bytes\n");
        return NULL;
      } else {
        /* we filled the chunk buffer without finding a start code */
        lprintf("Buffer full\n");
        parser->code = 0xb4;        /* sequence_error_code */
        parser->chunk_ptr = parser->chunk_buffer;
        return current;
      }
    }
    lprintf("New chunk: 0x%2X\n", byte);
    parser->chunk_ptr = chunk_ptr;
    parser->shift = 0xffffff00;
    parser->code = byte;
    return current;
  }
}


uint8_t *mpeg_parser_decode_data (mpeg_parser_t *parser,
                                  uint8_t *current, uint8_t *end,
                                  int *flush)
{
  int ret;
  uint8_t code;

  ret = 0;
  *flush = 0;
  
  while (current != end) {
    if (parser->chunk_ptr == parser->chunk_buffer) {
      /* write the beginning of the chunk */
      parser->chunk_buffer[0] = 0x00;
      parser->chunk_buffer[1] = 0x00;
      parser->chunk_buffer[2] = 0x01;
      parser->chunk_buffer[3] = parser->code;
      parser->chunk_ptr += 4;
      parser->chunk_start = parser->chunk_ptr;
      parser->has_sequence = 0;
    }
    
    code = parser->code;
    
    current = copy_chunk (parser, current, end);
    if (current == NULL)
      return NULL;
    ret = parse_chunk (parser, code, parser->chunk_start,
                       parser->chunk_ptr - parser->chunk_start - 4);
    parser->chunk_start = parser->chunk_ptr;
    if (ret == 1) {
      if (parser->has_sequence) {
        parser->frame_aspect_ratio = get_aspect_ratio(parser);
      }
      parser->buffer_size = parser->chunk_ptr - parser->chunk_buffer - 4;
      parser->chunk_ptr = parser->chunk_buffer;
      
      if (parser->code == 0xb7) /* sequence end, maybe a still menu */
        *flush = 1;
      
      return current;
    }
  }

  return NULL;
}

--- NEW FILE: dvaudio_decoder.c ---
/*
 * Copyright (C) 2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 * $Id: dvaudio_decoder.c,v 1.1 2005/04/04 22:29:51 dsalt-guest Exp $
 *
 * dv audio decoder based on patch by Dan Dennedy <dan@dennedy.org>
 *
 */
 
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <pthread.h>
#include <math.h>

#define LOG_MODULE "dvaudio"
#define LOG_VERBOSE
/*
#define LOG
*/

#include "xine_internal.h"
#include "buffer.h"
#include "xineutils.h"

#ifdef _MSC_VER
/* ffmpeg has own definitions of those types */
#  undef int8_t
#  undef uint8_t
#  undef int16_t
#  undef uint16_t
#  undef int32_t
#  undef uint32_t
#  undef int64_t
#  undef uint64_t
#endif

#ifdef HAVE_FFMPEG
#  include <avcodec.h>
#  include "libavcodec/dvdata.h"
#else
#  include "libavcodec/avcodec.h"
#  include "libavcodec/dvdata.h"
#endif

#ifdef _MSC_VER
#  undef malloc
#  undef free
#  undef realloc
#endif

#define AUDIOBUFSIZE 128*1024
#define MAXFRAMESIZE 131072


typedef struct {
  audio_decoder_class_t   decoder_class;
} dvaudio_class_t;

typedef struct dvaudio_decoder_s {
  audio_decoder_t   audio_decoder;

  xine_stream_t    *stream;

  int               output_open;
  int               audio_channels;
  int               audio_bits;
  int               audio_sample_rate;

  unsigned char    *buf;
  int               bufsize;
  int               size;

  char             *decode_buffer;
  int               decoder_ok;

} dvaudio_decoder_t;


enum dv_pack_type {
     dv_header525     = 0x3f, /* see dv_write_pack for important details on */
     dv_header625     = 0xbf, /* these two packs */
     dv_timecode      = 0x13,
     dv_audio_source  = 0x50,
     dv_audio_control = 0x51,
     dv_audio_recdate = 0x52,
     dv_audio_rectime = 0x53,
     dv_video_source  = 0x60,
     dv_video_control = 0x61,
     dv_viedo_recdate = 0x62,
     dv_video_rectime = 0x63,
     dv_unknown_pack  = 0xff,
};


/*
 * This is the dumbest implementation of all -- it simply looks at
 * a fixed offset and if pack isn't there -- fails. We might want
 * to have a fallback mechanism for complete search of missing packs.
 */
static const uint8_t* dv_extract_pack(uint8_t* frame, enum dv_pack_type t)
{
    int offs;

    switch (t) {
    case dv_audio_source:
          offs = (80*6 + 80*16*3 + 3);
	  break;
    case dv_audio_control:
          offs = (80*6 + 80*16*4 + 3);
	  break;
    case dv_video_control:
          offs = (80*5 + 48 + 5);
          break;
    default:
          return NULL;
    }

    return (frame[offs] == t ? &frame[offs] : NULL);
}

static inline uint16_t dv_audio_12to16(uint16_t sample)
{
    uint16_t shift, result;

    sample = (sample < 0x800) ? sample : sample | 0xf000;
    shift = (sample & 0xf00) >> 8;

    if (shift < 0x2 || shift > 0xd) {
	result = sample;
    } else if (shift < 0x8) {
        shift--;
	result = (sample - (256 * shift)) << shift;
    } else {
	shift = 0xe - shift;
	result = ((sample + ((256 * shift) + 1)) << shift) - 1;
    }

    return result;
}

/*
 * There's a couple of assumptions being made here:
 * 1. By default we silence erroneous (0x8000/16bit 0x800/12bit) audio samples.
 *    We can pass them upwards when ffmpeg will be ready to deal with them.
 * 2. We don't do software emphasis.
 * 3. Audio is always returned as 16bit linear samples: 12bit nonlinear samples
 *    are converted into 16bit linear ones.
 */
static int dv_extract_audio(uint8_t* frame, uint8_t* pcm, uint8_t* pcm2)
{
    int size, i, j, d, of, smpls, freq, quant, half_ch;
    uint16_t lc, rc;
    const DVprofile* sys;
    const uint8_t* as_pack;

    as_pack = dv_extract_pack(frame, dv_audio_source);
    if (!as_pack)    /* No audio ? */
	return 0;

    sys = dv_frame_profile(frame);
    smpls = as_pack[1] & 0x3f; /* samples in this frame - min. samples */
    freq = (as_pack[4] >> 3) & 0x07; /* 0 - 48KHz, 1 - 44,1kHz, 2 - 32 kHz */
    quant = as_pack[4] & 0x07; /* 0 - 16bit linear, 1 - 12bit nonlinear */

    if (quant > 1)
	return -1; /* Unsupported quantization */

    size = (sys->audio_min_samples[freq] + smpls) * 4; /* 2ch, 2bytes */
    half_ch = sys->difseg_size/2;

    /* for each DIF segment */
    for (i = 0; i < sys->difseg_size; i++) {
       frame += 6 * 80; /* skip DIF segment header */
       if (quant == 1 && i == half_ch) {
           if (!pcm2)
               break;
           else
               pcm = pcm2;
       }

       for (j = 0; j < 9; j++) {
          for (d = 8; d < 80; d += 2) {
	     if (quant == 0) {  /* 16bit quantization */
		 of = sys->audio_shuffle[i][j] + (d - 8)/2 * sys->audio_stride;
                 if (of*2 >= size)
		     continue;

#ifdef WORDS_BIGENDIAN
		 pcm[of*2] = frame[d];
		 pcm[of*2+1] = frame[d+1];
#else
		 pcm[of*2] = frame[d+1];
		 pcm[of*2+1] = frame[d];
#endif
		 if (pcm[of*2+1] == 0x80 && pcm[of*2] == 0x00)
		     pcm[of*2+1] = 0;
	      } else {           /* 12bit quantization */
		 lc = ((uint16_t)frame[d] << 4) |
		      ((uint16_t)frame[d+2] >> 4);
		 rc = ((uint16_t)frame[d+1] << 4) |
	              ((uint16_t)frame[d+2] & 0x0f);
		 lc = (lc == 0x800 ? 0 : dv_audio_12to16(lc));
		 rc = (rc == 0x800 ? 0 : dv_audio_12to16(rc));

		 of = sys->audio_shuffle[i%half_ch][j] + (d - 8)/3 * sys->audio_stride;
                 if (of*2 >= size)
		     continue;

#ifdef WORDS_BIGENDIAN
		 pcm[of*2] = lc >> 8;
		 pcm[of*2+1] = lc & 0xff;
#else
		 pcm[of*2] = lc & 0xff;
		 pcm[of*2+1] = lc >> 8;
#endif
		 of = sys->audio_shuffle[i%half_ch+half_ch][j] +
		      (d - 8)/3 * sys->audio_stride;
#ifdef WORDS_BIGENDIAN
		 pcm[of*2] = rc >> 8;
		 pcm[of*2+1] = rc & 0xff;
#else
		 pcm[of*2] = rc & 0xff;
		 pcm[of*2+1] = rc >> 8;
#endif
		 ++d;
	      }
	  }

	  frame += 16 * 80; /* 15 Video DIFs + 1 Audio DIF */
        }
    }

    return size;
}

static void dvaudio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {

  dvaudio_decoder_t *this = (dvaudio_decoder_t *) this_gen;
  int bytes_consumed;
  int decode_buffer_size;
  int offset;
  int out;
  audio_buffer_t *audio_buffer;
  int bytes_to_send;
  
  if (buf->decoder_flags & BUF_FLAG_PREVIEW)
    return;
      
  if (buf->decoder_flags & BUF_FLAG_STDHEADER) {
    this->buf = xine_xmalloc(AUDIOBUFSIZE);
    this->bufsize = AUDIOBUFSIZE;
    this->size = 0;
    this->decode_buffer = xine_xmalloc(MAXFRAMESIZE);
    
    this->audio_sample_rate = buf->decoder_info[1];
    this->audio_bits = buf->decoder_info[2];
    this->audio_channels = buf->decoder_info[3];
    
    _x_meta_info_set_utf8(this->stream, XINE_META_INFO_AUDIOCODEC, "DV Audio");
    
    this->decoder_ok = 1;
   
    return;
  }
  
  if (this->decoder_ok && !(buf->decoder_flags & (BUF_FLAG_HEADER|BUF_FLAG_SPECIAL))) {
    
    if (!this->output_open) {
      this->output_open = this->stream->audio_out->open(this->stream->audio_out,
        this->stream, this->audio_bits, this->audio_sample_rate,
        (this->audio_channels == 2) ? AO_CAP_MODE_STEREO : AO_CAP_MODE_MONO);
    }

    /* if the audio still isn't open, bail */
    if (!this->output_open)
      return;
      
    if( this->size + buf->size > this->bufsize ) {
      this->bufsize = this->size + 2 * buf->size;
      xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
              _("dvaudio: increasing buffer to %d to avoid overflow.\n"), 
              this->bufsize);
      this->buf = realloc( this->buf, this->bufsize );
    }

    xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size);
    this->size += buf->size;

    if (buf->decoder_flags & BUF_FLAG_FRAME_END) { /* time to decode a frame */

      offset = 0;
      while (this->size>0) {
        decode_buffer_size = dv_extract_audio(&this->buf[offset], this->decode_buffer, NULL);

        if (decode_buffer_size > -1)
          bytes_consumed = dv_frame_profile(&this->buf[offset])->frame_size;
        else
          bytes_consumed = decode_buffer_size;
        
        /* dispatch the decoded audio */
        out = 0;
        while (out < decode_buffer_size) {
          audio_buffer = 
            this->stream->audio_out->get_buffer (this->stream->audio_out);
          if (audio_buffer->mem_size == 0) {
            xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, 
                     "dvaudio: Help! Allocated audio buffer with nothing in it!\n");
            return;
          }

          if ((decode_buffer_size - out) > audio_buffer->mem_size)
            bytes_to_send = audio_buffer->mem_size;
          else
            bytes_to_send = decode_buffer_size - out;

          /* fill up this buffer */
          xine_fast_memcpy(audio_buffer->mem, &this->decode_buffer[out],
            bytes_to_send);
          /* byte count / 2 (bytes / sample) / channels */
          audio_buffer->num_frames = bytes_to_send / 2 / this->audio_channels;

          audio_buffer->vpts = buf->pts;
          buf->pts = 0;  /* only first buffer gets the real pts */
          this->stream->audio_out->put_buffer (this->stream->audio_out,
            audio_buffer, this->stream);

          out += bytes_to_send;
        }

        this->size -= bytes_consumed;
        offset += bytes_consumed;
      }

      /* reset internal accumulation buffer */
      this->size = 0;
    }
  }
}

static void dvaudio_reset (audio_decoder_t *this_gen) {
  dvaudio_decoder_t *this = (dvaudio_decoder_t *) this_gen;
  
  this->size = 0;
}

static void dvaudio_discontinuity (audio_decoder_t *this_gen) {
}

static void dvaudio_dispose (audio_decoder_t *this_gen) {

  dvaudio_decoder_t *this = (dvaudio_decoder_t *) this_gen;
  
  if (this->output_open)
    this->stream->audio_out->close (this->stream->audio_out, this->stream);
  this->output_open = 0;

  free(this->buf);
  free(this->decode_buffer);

  free (this_gen);
}

static audio_decoder_t *dvaudio_open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) {

  dvaudio_decoder_t *this ;

  this = (dvaudio_decoder_t *) xine_xmalloc (sizeof (dvaudio_decoder_t));

  this->audio_decoder.decode_data    = dvaudio_decode_data;
  this->audio_decoder.reset          = dvaudio_reset;
  this->audio_decoder.discontinuity  = dvaudio_discontinuity;
  this->audio_decoder.dispose        = dvaudio_dispose;

  this->output_open = 0;
  this->audio_channels = 0;
  this->stream = stream;
  this->buf = NULL;
  this->size = 0;
  this->decoder_ok = 0;
  
  return &this->audio_decoder;
}

static char *dvaudio_get_identifier (audio_decoder_class_t *this) {
  return "dv audio";
}

static char *dvaudio_get_description (audio_decoder_class_t *this) {
  return "dv audio decoder plugin";
}

static void dvaudio_dispose_class (audio_decoder_class_t *this) {
  free (this);
}

static void *init_dvaudio_plugin (xine_t *xine, void *data) {

  dvaudio_class_t *this ;

  this = (dvaudio_class_t *) xine_xmalloc (sizeof (dvaudio_class_t));

  this->decoder_class.open_plugin     = dvaudio_open_plugin;
  this->decoder_class.get_identifier  = dvaudio_get_identifier;
  this->decoder_class.get_description = dvaudio_get_description;
  this->decoder_class.dispose         = dvaudio_dispose_class;

  return this;
}

static uint32_t supported_audio_types[] = { 
  BUF_AUDIO_DV,
  0
};

decoder_info_t dec_info_dvaudio = {
  supported_audio_types,   /* supported types */
  5                        /* priority        */
};
    
/*
 * exported plugin catalog entry
 */

plugin_info_t xine_plugin_info[] = {
  /* type, API, "name", version, special_info, init_function */  
  { PLUGIN_AUDIO_DECODER, 15, "dvaudio", XINE_VERSION_CODE, &dec_info_dvaudio, init_dvaudio_plugin },
  { PLUGIN_NONE, 0, "", 0, NULL, NULL }
};

--- NEW FILE: video_decoder.c ---
/*
 * Copyright (C) 2001-2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
[...1308 lines suppressed...]
  BUF_VIDEO_FLV1,
  BUF_VIDEO_QTRLE,
  BUF_VIDEO_H264,
  0 
};

static uint32_t wmv8_video_types[] = { 
  BUF_VIDEO_WMV8,
  0 
};

decoder_info_t dec_info_ffmpeg_video = {
  supported_video_types,   /* supported types */
  6                        /* priority        */
};

decoder_info_t dec_info_ffmpeg_wmv8 = {
  wmv8_video_types,        /* supported types */
  0                        /* priority        */
};

--- NEW FILE: mpeg_parser.h ---
/*
 * Copyright (C) 2001-2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 * Simple MPEG-ES parser/framer by Thibaut Mattern (tmattern@noos.fr)
 *   based on libmpeg2 decoder.
 *
 * $Id: mpeg_parser.h,v 1.1 2005/04/04 22:29:51 dsalt-guest Exp $
 */
#ifndef HAVE_MPEG_PARSER_H
#define HAVE_MPEG_PARSER_H

#include "xine_internal.h"
#include "xine_decoder.h"

#define BUFFER_SIZE (1194 * 1024) /* libmpeg2's buffer size */

/* picture coding type (mpeg2 header) */
#define I_TYPE 1
#define P_TYPE 2
#define B_TYPE 3
#define D_TYPE 4

typedef struct mpeg_parser_s {
  uint32_t        shift;
  int             is_sequence_needed;
  uint8_t         chunk_buffer[BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE];
  uint8_t        *chunk_ptr;
  uint8_t        *chunk_start;
  int             buffer_size;
  uint8_t         code;
  uint8_t         picture_coding_type;
  int             rate_code;
  int             aspect_ratio_info;
  int             in_slice;

  /* public properties */
  int             is_mpeg1;
  int             has_sequence;
  int             width;
  int             height;
  int             frame_duration;
  double          frame_aspect_ratio;

} mpeg_parser_t;

/* parser initialization */
void mpeg_parser_init (mpeg_parser_t *parser);

/* read a frame
 *   return a pointer to the first byte of the next frame
 *   or NULL if more bytes are needed
 *   *flush is set to 1 if the decoder must be flushed (needed for still menus)
 */
uint8_t *mpeg_parser_decode_data (mpeg_parser_t *parser,
                                  uint8_t *current, uint8_t *end,
                                  int *flush);

/* reset the parser */
void mpeg_parser_reset (mpeg_parser_t *parser);

#endif /* HAVE_MPEG_PARSER_H */

--- NEW FILE: Makefile.am ---
include $(top_srcdir)/misc/Makefile.common

if HAVE_FFMPEG
FF_CPPFLAGS = $(FFMPEG_CPPFLAGS)
link_ffmpeg = $(FFMPEG_LIBS)
else
link_ffmpeg = \
  $(top_builddir)/src/libffmpeg/libavcodec/libavcodec.la \
  $(top_builddir)/src/libffmpeg/libavcodec/libpostproc/libpostprocess.la
SUBDIRS = libavcodec
endif

# this must always be included, even if the current machine has no DXR3...
EXTRA_DIST = xine_encoder.c diff_to_ffmpeg_cvs.txt

INTERNAL_DOCS = diff_to_ffmpeg_cvs.txt

libdir = $(XINE_PLUGINDIR)

lib_LTLIBRARIES = xineplug_decode_ff.la xineplug_decode_dvaudio.la

if HAVE_DXR3
AM_CPPFLAGS = -I$(top_srcdir)/src/dxr3 $(X_CFLAGS) $(FF_CPPFLAGS)
xineplug_decode_ff_la_SOURCES = xine_decoder.c audio_decoder.c video_decoder.c \
                                xine_encoder.c mpeg_parser.c
# The dxr3 uses ffmpegs MPEG encoder by dlopen()ing the ffmpeg plugin and
# dlsym()ing the necessary function. Therefore we must allow more exported
# symbols and cannot use @XINE_PLUGIN_MIN_SYMS@
xineplug_decode_ff_la_LDFLAGS = -avoid-version -module
else
AM_CPPFLAGS = $(FF_CPPFLAGS)
xineplug_decode_ff_la_SOURCES = xine_decoder.c audio_decoder.c video_decoder.c \
                                mpeg_parser.c
xineplug_decode_ff_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@
endif

xineplug_decode_ff_la_LIBADD = $(MLIB_LIBS) $(XINE_LIB) -lm $(ZLIB_LIBS) \
	$(link_ffmpeg)

xineplug_decode_dvaudio_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@
xineplug_decode_dvaudio_la_SOURCES = dvaudio_decoder.c
xineplug_decode_dvaudio_la_LIBADD  = $(XINE_LIB)

noinst_HEADERS = xine_decoder.h mpeg_parser.h

--- NEW FILE: diff_to_ffmpeg_cvs.txt ---
--- avcodec.h	2004-05-28 18:20:57.000000000 +0200
+++ avcodec.h	2004-05-28 18:25:10.000000000 +0200
@@ -15,6 +15,13 @@
 #include "rational.h"
 #include <sys/types.h> /* size_t */
 
+/* FIXME: We cannot use ffmpeg's XvMC capabilities, since that would require
+ * linking the ffmpeg plugin against XvMC libraries, which is a bad thing,
+ * since they are output dependend.
+ * The correct fix would be to reimplement the XvMC functions libavcodec uses
+ * and do the necessary talking with our XvMC output plugin there. */
+#undef HAVE_XVMC
+
 #define FFMPEG_VERSION_INT     0x000408
 #define FFMPEG_VERSION         "0.4.8"
 #define LIBAVCODEC_BUILD       4715
@@ -2177,6 +2184,13 @@
                     ((uint8_t*)(x))[0])
 #endif
 
+/* unused static macro */
+#if defined(__GNUC__) && !defined(DEBUG)
+/* since we do not compile the encoder part of ffmpeg, some static
+ * functions will be unused; this is ok, the compiler will take care */
+#  define static static __attribute__((__unused__))
+#endif
+
 #ifdef __cplusplus
 }
 #endif
--- common.h	2004-05-28 18:20:57.000000000 +0200
+++ common.h	2004-05-28 18:22:54.000000000 +0200
@@ -6,6 +6,11 @@
 #ifndef COMMON_H
 #define COMMON_H
 
+/* xine: disable DEBUG for ffmpeg (too noisy) */
+#ifdef DEBUG
+#undef DEBUG
+#endif
+
 #if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
 #    define CONFIG_WIN32
 #endif
@@ -213,7 +218,9 @@
 /* debug stuff */
 
 #    ifndef DEBUG
+#      ifndef NDEBUG
 #        define NDEBUG
+#      endif
 #    endif
 #    include <assert.h>
 
--- dsputil.h	2004-05-28 18:20:57.000000000 +0200
+++ dsputil.h	2004-05-28 18:22:54.000000000 +0200
@@ -31,6 +31,9 @@
 #include "common.h"
 #include "avcodec.h"
 
+#if defined(ARCH_X86)
+#define HAVE_MMX 1
+#endif
 
 //#define DEBUG
 /* dct code */
--- mlib/dsputil_mlib.c	2004-05-28 18:20:57.000000000 +0200
+++ mlib/dsputil_mlib.c	2004-05-28 18:22:54.000000000 +0200
@@ -20,6 +20,8 @@
 #include "../dsputil.h"
 #include "../mpegvideo.h"
 
+#include "../../../xine-utils/xineutils.h"
+
 #include <mlib_types.h>
 #include <mlib_status.h>
 #include <mlib_sys.h>
@@ -419,6 +421,7 @@
 
 void dsputil_init_mlib(DSPContext* c, AVCodecContext *avctx)
 {
+  if (xine_mm_accel() & MM_ACCEL_MLIB) {
     c->get_pixels  = get_pixels_mlib;
     c->diff_pixels = diff_pixels_mlib;
     c->add_pixels_clamped = add_pixels_clamped_mlib;
@@ -445,10 +448,12 @@
     c->put_no_rnd_pixels_tab[1][0] = put_pixels8_mlib;
 
     c->bswap_buf = bswap_buf_mlib;
+  }
 }
 
 void MPV_common_init_mlib(MpegEncContext *s)
 {
+  if (xine_mm_accel() & MM_ACCEL_MLIB) {
     if(s->avctx->dct_algo==FF_DCT_AUTO || s->avctx->dct_algo==FF_DCT_MLIB){
 	s->dsp.fdct = ff_fdct_mlib;
     }
@@ -459,4 +464,5 @@
         s->dsp.idct    = ff_idct_mlib;
         s->dsp.idct_permutation_type= FF_NO_IDCT_PERM;
     }
+  }
 }
--- motion_est.c	2004-05-30 20:16:44.000000000 +0200
+++ motion_est.c	2004-05-10 23:21:24.000000000 +0200
@@ -20,6 +20,9 @@
  *
  * new Motion Estimation (X1/EPZS) by Michael Niedermayer <michaelni@gmx.at>
  */
+
+/* motion estimation only needed for encoders */
+#ifdef CONFIG_ENCODERS
  
 /**
  * @file motion_est.c
@@ -1998,3 +2001,5 @@
         }
     }
 }
+
+#endif /* CONFIG_ENCODERS */
--- mpeg12.c	2004-05-28 18:20:57.000000000 +0200
+++ mpeg12.c	2004-05-28 18:22:54.000000000 +0200
@@ -34,6 +34,13 @@
 //#include <assert.h>
 
 
+/* if xine's MPEG encoder is enabled, enable the encoding features in
+ * this particular module */
+#if defined(XINE_MPEG_ENCODER) && !defined(CONFIG_ENCODERS)
+#define CONFIG_ENCODERS
+#endif
+
+
 /* Start codes. */
 #define SEQ_END_CODE		0x000001b7
 #define SEQ_START_CODE		0x000001b3
--- mpegvideo.c	2004-08-04 18:17:52.000000000 +0200
+++ mpegvideo.c	2004-08-04 18:19:08.000000000 +0200
@@ -38,6 +38,14 @@
 //#undef NDEBUG
 //#include <assert.h>
 
+
+/* if xine's MPEG encoder is enabled, enable the encoding features in
+ * this particular module */
+#if defined(XINE_MPEG_ENCODER) && !defined(CONFIG_ENCODERS)
+#define CONFIG_ENCODERS
+#endif
+
+
 #ifdef CONFIG_ENCODERS
 static void encode_picture(MpegEncContext *s, int picture_number);
 #endif //CONFIG_ENCODERS
@@ -1032,6 +1040,8 @@
         s->low_delay= 0; //s->max_b_frames ? 0 : 1;
         avctx->delay= s->low_delay ? 0 : (s->max_b_frames + 1);
         break;
+/* xine: this is never used in either decode or MPEG-1 encode mode */
+#if 0
     case CODEC_ID_MPEG2VIDEO:
         s->out_format = FMT_MPEG1;
         s->low_delay= 0; //s->max_b_frames ? 0 : 1;
@@ -1153,6 +1163,7 @@
         s->low_delay=1;
         break;
 #endif
+#endif /* #if 0 */
     default:
         return -1;
     }
@@ -1171,13 +1182,22 @@
     
     ff_set_cmp(&s->dsp, s->dsp.ildct_cmp, s->avctx->ildct_cmp);
     
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
+    ff_init_me(s);
+#endif /* #if 0 */
+
 #ifdef CONFIG_ENCODERS
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
 #ifdef CONFIG_RISKY
     if (s->out_format == FMT_H263)
         h263_encode_init(s);
     if(s->msmpeg4_version)
         ff_msmpeg4_encode_init(s);
 #endif
+#endif /* #if 0 */
+/* xine: we do want this for MPEG-1 encoding */
     if (s->out_format == FMT_MPEG1)
         ff_mpeg1_encode_init(s);
 #endif
@@ -1229,9 +1249,12 @@
 
     ff_rate_control_uninit(s);
 
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
     MPV_common_end(s);
     if (s->out_format == FMT_MJPEG)
         mjpeg_close(s);
+#endif /* #if 0 */
 
     av_freep(&avctx->extradata);
       
@@ -2135,8 +2158,11 @@
 
         MPV_frame_end(s);
 
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
         if (s->out_format == FMT_MJPEG)
             mjpeg_picture_trailer(s);
+#endif /* #if 0 */
         
         if(s->flags&CODEC_FLAG_PASS1)
             ff_write_pass1_stats(s);
@@ -3673,6 +3699,8 @@
     case CODEC_ID_MPEG1VIDEO:
     case CODEC_ID_MPEG2VIDEO:
         mpeg1_encode_mb(s, s->block, motion_x, motion_y); break;
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
 #ifdef CONFIG_RISKY
     case CODEC_ID_MPEG4:
         mpeg4_encode_mb(s, s->block, motion_x, motion_y); break;
@@ -3690,6 +3718,7 @@
 #endif
     case CODEC_ID_MJPEG:
         mjpeg_encode_mb(s, s->block); break;
+#endif /* #if 0 */
     default:
         assert(0);
     }
@@ -3897,6 +3926,8 @@
                +sse(s, s->new_picture.data[2] + s->mb_x*8  + s->mb_y*s->uvlinesize*8,s->dest[2], w>>1, h>>1, s->uvlinesize);
 }
 
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
 static int pre_estimate_motion_thread(AVCodecContext *c, void *arg){
     MpegEncContext *s= arg;
 
@@ -3940,6 +3971,7 @@
     }
     return 0;
 }
+#endif
 
 static int mb_var_thread(AVCodecContext *c, void *arg){
     MpegEncContext *s= arg;
@@ -3964,6 +3996,8 @@
 }
 
 static void write_slice_end(MpegEncContext *s){
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
     if(s->codec_id==CODEC_ID_MPEG4){
         if(s->partitioned_frame){
             ff_mpeg4_merge_partitions(s);
@@ -3973,6 +4007,7 @@
     }else if(s->out_format == FMT_MJPEG){
         ff_mjpeg_stuffing(&s->pb);
     }
+#endif /* #if 0 */
 
     align_put_bits(&s->pb);
     flush_put_bits(&s->pb);
@@ -4024,10 +4059,13 @@
     case CODEC_ID_FLV1:
         s->gob_index = ff_h263_get_gob_height(s);
         break;
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
     case CODEC_ID_MPEG4:
         if(s->partitioned_frame)
             ff_mpeg4_init_partitions(s);
         break;
+#endif /* #if 0 */
     }
 #endif
 
@@ -4081,9 +4119,12 @@
                     if(s->start_mb_y != mb_y || mb_x!=0){
                         write_slice_end(s);
 
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
                         if(s->codec_id==CODEC_ID_MPEG4 && s->partitioned_frame){
                             ff_mpeg4_init_partitions(s);
                         }
+#endif /* #if 0 */
                     }
                 
                     assert((put_bits_count(&s->pb)&7) == 0);
@@ -4105,19 +4146,25 @@
                         s->avctx->rtp_callback(s->avctx, s->ptr_lastgob, current_packet_size, 0);
                     
                     switch(s->codec_id){
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
                     case CODEC_ID_MPEG4:
                         ff_mpeg4_encode_video_packet_header(s);
                         ff_mpeg4_clean_buffers(s);
                     break;
+#endif /* #if 0 */
                     case CODEC_ID_MPEG1VIDEO:
                     case CODEC_ID_MPEG2VIDEO:
                         ff_mpeg1_encode_slice_header(s);
                         ff_mpeg1_clean_buffers(s);
                     break;
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
                     case CODEC_ID_H263:
                     case CODEC_ID_H263P:
                         h263_encode_gob_header(s, mb_y);                       
                     break;
+#endif /* #if 0 */
                     }
 
                     if(s->flags&CODEC_FLAG_PASS1){
@@ -4231,9 +4278,12 @@
                     
                     s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD | MV_DIRECT;
                     s->mb_intra= 0;
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
 #ifdef CONFIG_RISKY
                     ff_mpeg4_set_direct_mv(s, mx, my);
 #endif
+#endif /* #if 0 */
                     encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_DIRECT, pb, pb2, tex_pb, 
                                  &dmin, &next_block, mx, my);
                 }
@@ -4421,9 +4471,12 @@
                     s->mb_intra= 0;
                     motion_x=s->b_direct_mv_table[xy][0];
                     motion_y=s->b_direct_mv_table[xy][1];
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
 #ifdef CONFIG_RISKY
                     ff_mpeg4_set_direct_mv(s, motion_x, motion_y);
 #endif
+#endif /* #if 0 */
                     break;
                 case CANDIDATE_MB_TYPE_BIDIR:
                     s->mv_dir = MV_DIR_FORWARD | MV_DIR_BACKWARD;
@@ -4530,11 +4583,14 @@
         }
     }
 
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
 #ifdef CONFIG_RISKY
     //not beautifull here but we must write it before flushing so it has to be here
     if (s->msmpeg4_version && s->msmpeg4_version<4 && s->pict_type == I_TYPE)
         msmpeg4_encode_ext_header(s);
 #endif
+#endif /* #if 0 */
 
     write_slice_end(s);
 
@@ -4597,12 +4653,15 @@
     s->me.mb_var_sum_temp    =
     s->me.mc_mb_var_sum_temp = 0;
 
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
 #ifdef CONFIG_RISKY
     /* we need to initialize some time vars before we can encode b-frames */
     // RAL: Condition added for MPEG1VIDEO
     if (s->codec_id == CODEC_ID_MPEG1VIDEO || s->codec_id == CODEC_ID_MPEG2VIDEO || (s->h263_pred && !s->h263_msmpeg4))
         ff_set_mpeg4_time(s, s->picture_number);  //FIXME rename and use has_b_frames or similar
 #endif
+#endif /* #if 0 */
         
     s->me.scene_change_score=0;
     
@@ -4621,6 +4680,8 @@
         ff_update_duplicate_context(s->thread_context[i], s);
     }
 
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
     ff_init_me(s);
 
     /* Estimate motion for every MB */
@@ -4633,6 +4694,8 @@
 
         s->avctx->execute(s->avctx, estimate_motion_thread, (void**)&(s->thread_context[0]), NULL, s->avctx->thread_count);
     }else /* if(s->pict_type == I_TYPE) */{
+#endif /* #if 0 */
+    {
         /* I-Frame */
         for(i=0; i<s->mb_stride*s->mb_height; i++)
             s->mb_type[i]= CANDIDATE_MB_TYPE_INTRA;
@@ -4656,6 +4719,8 @@
 //printf("Scene change detected, encoding as I Frame %d %d\n", s->current_picture.mb_var_sum, s->current_picture.mc_mb_var_sum);
     }
 
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
     if(!s->umvplus){
         if(s->pict_type==P_TYPE || s->pict_type==S_TYPE) {
             s->f_code= ff_get_best_fcode(s, s->p_mv_table, CANDIDATE_MB_TYPE_INTER);
@@ -4709,11 +4774,14 @@
             }
         }
     }
+#endif /* #if 0 */
 
     if (!s->fixed_qscale) 
         s->current_picture.quality = ff_rate_estimate_qscale(s); //FIXME pic_ptr
 
     if(s->adaptive_quant){
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
 #ifdef CONFIG_RISKY
         switch(s->codec_id){
         case CODEC_ID_MPEG4:
@@ -4726,6 +4794,7 @@
             break;
         }
 #endif
+#endif /* #if 0 */
 
         s->lambda= s->lambda_table[0];
         //FIXME broken
@@ -4759,6 +4828,8 @@
 
     s->last_bits= put_bits_count(&s->pb);
     switch(s->out_format) {
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
     case FMT_MJPEG:
         mjpeg_picture_header(s);
         break;
@@ -4778,11 +4849,15 @@
             h263_encode_picture_header(s, picture_number);
         break;
 #endif
+#endif /* #if 0 */
     case FMT_MPEG1:
         mpeg1_encode_picture_header(s, picture_number);
         break;
+/* xine: do not need this for decode or MPEG-1 encoding modes */
+#if 0
     case FMT_H264:
         break;
+#endif /* #if 0 */
     default:
         assert(0);
     }

--- NEW FILE: audio_decoder.c ---
/*
 * Copyright (C) 2001-2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 * $Id: audio_decoder.c,v 1.1 2005/04/04 22:29:51 dsalt-guest Exp $
 *
 * xine audio decoder plugin using ffmpeg
 *
 */
 
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <pthread.h>
#include <math.h>

#define LOG_MODULE "ffmpeg_audio_dec"
#define LOG_VERBOSE
/*
#define LOG
*/

#include "xine_internal.h"
#include "buffer.h"
#include "xineutils.h"
#include "bswap.h"
#include "xine_decoder.h"

#define AUDIOBUFSIZE (64 * 1024)

typedef struct {
  audio_decoder_class_t   decoder_class;
} ff_audio_class_t;

typedef struct ff_audio_decoder_s {
  audio_decoder_t   audio_decoder;

  xine_stream_t    *stream;

  int               output_open;
  int               audio_channels;
  int               audio_bits;
  int               audio_sample_rate;

  unsigned char    *buf;
  int               bufsize;
  int               size;

  AVCodecContext    *context;
  AVCodec           *codec;
  
  char              *decode_buffer;
  int               decoder_ok;

} ff_audio_decoder_t;


static const ff_codec_t ff_audio_lookup[] = {
  {BUF_AUDIO_WMAV1,      CODEC_ID_WMAV1,          "MS Windows Media Audio 1 (ffmpeg)"},
  {BUF_AUDIO_WMAV2,      CODEC_ID_WMAV2,          "MS Windows Media Audio 2 (ffmpeg)"},
  {BUF_AUDIO_14_4,       CODEC_ID_RA_144,         "Real 14.4 (ffmpeg)"},
  {BUF_AUDIO_28_8,       CODEC_ID_RA_288,         "Real 28.8 (ffmpeg)"},
  {BUF_AUDIO_MPEG,       CODEC_ID_MP3,            "MP3 (ffmpeg)"},
  {BUF_AUDIO_MSADPCM,    CODEC_ID_ADPCM_MS,       "MS ADPCM (ffmpeg)"},
  {BUF_AUDIO_QTIMAADPCM, CODEC_ID_ADPCM_IMA_QT,   "QT IMA ADPCM (ffmpeg)"},
  {BUF_AUDIO_MSIMAADPCM, CODEC_ID_ADPCM_IMA_WAV,  "MS IMA ADPCM (ffmpeg)"},
  {BUF_AUDIO_DK3ADPCM,   CODEC_ID_ADPCM_IMA_DK3,  "Duck DK3 ADPCM (ffmpeg)"},
  {BUF_AUDIO_DK4ADPCM,   CODEC_ID_ADPCM_IMA_DK4,  "Duck DK4 ADPCM (ffmpeg)"},
  {BUF_AUDIO_VQA_IMA,    CODEC_ID_ADPCM_IMA_WS,   "Westwood Studios IMA (ffmpeg)"},
  {BUF_AUDIO_SMJPEG_IMA, CODEC_ID_ADPCM_IMA_SMJPEG, "SMJPEG IMA (ffmpeg)"},
  {BUF_AUDIO_XA_ADPCM,   CODEC_ID_ADPCM_XA,       "CD-ROM/XA ADPCM (ffmpeg)"},
  {BUF_AUDIO_4X_ADPCM,   CODEC_ID_ADPCM_4XM,      "4X ADPCM (ffmpeg)"},
  {BUF_AUDIO_EA_ADPCM,   CODEC_ID_ADPCM_EA,       "Electronic Arts ADPCM (ffmpeg)"},
  {BUF_AUDIO_MULAW,      CODEC_ID_PCM_MULAW,      "mu-law logarithmic PCM (ffmpeg)"},
  {BUF_AUDIO_ALAW,       CODEC_ID_PCM_ALAW,       "A-law logarithmic PCM (ffmpeg)"},
  {BUF_AUDIO_ROQ,        CODEC_ID_ROQ_DPCM,       "RoQ DPCM (ffmpeg)"},
  {BUF_AUDIO_INTERPLAY,  CODEC_ID_INTERPLAY_DPCM, "Interplay DPCM (ffmpeg)"},
  {BUF_AUDIO_MAC3,       CODEC_ID_MACE3,          "MACE 3:1 (ffmpeg)"},
  {BUF_AUDIO_MAC6,       CODEC_ID_MACE6,          "MACE 6:1 (ffmpeg)"},
  {BUF_AUDIO_XAN_DPCM,   CODEC_ID_XAN_DPCM,       "Origin Xan DPCM (ffmpeg)"},
  {BUF_AUDIO_VMD,        CODEC_ID_VMDAUDIO,       "Sierra VMD Audio (ffmpeg)"},
  {BUF_AUDIO_FLAC,       CODEC_ID_FLAC,           "FLAC (ffmpeg)"} };


 static void ff_audio_ensure_buffer_size(ff_audio_decoder_t *this, int size) {
  if (size > this->bufsize) {
    this->bufsize = size + size / 2;
    xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
            _("ffmpeg_audio_dec: increasing buffer to %d to avoid overflow.\n"), 
            this->bufsize);
    this->buf = realloc( this->buf, this->bufsize );
  }
}

static void ff_audio_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {

  ff_audio_decoder_t *this = (ff_audio_decoder_t *) this_gen;
  int bytes_consumed;
  int decode_buffer_size;
  int offset;
  int out;
  audio_buffer_t *audio_buffer;
  int bytes_to_send;

  if (buf->decoder_flags & BUF_FLAG_HEADER) {

    /* accumulate init data */
    ff_audio_ensure_buffer_size(this, this->size + buf->size);
    memcpy(this->buf + this->size, buf->content, buf->size);
    this->size += buf->size;
    
    if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
      int i, codec_type;
      xine_waveformatex *audio_header;
  
      codec_type = buf->type & 0xFFFF0000;
      this->codec = NULL;
  
      for(i = 0; i < sizeof(ff_audio_lookup)/sizeof(ff_codec_t); i++)
        if(ff_audio_lookup[i].type == codec_type) {
          this->codec = avcodec_find_decoder(ff_audio_lookup[i].id);
          _x_meta_info_set(this->stream, XINE_META_INFO_AUDIOCODEC,
                           ff_audio_lookup[i].name);
          break;
        }
  
      if (!this->codec) {
        xprintf (this->stream->xine, XINE_VERBOSITY_LOG, 
                 _("ffmpeg_audio_dec: couldn't find ffmpeg decoder for buf type 0x%X\n"),
                 codec_type);
        _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_HANDLED, 0);
        return;
      }
  
      this->context = avcodec_alloc_context();
      
      if(buf->decoder_flags & BUF_FLAG_STDHEADER) {
        this->audio_sample_rate = buf->decoder_info[1];
        this->audio_channels    = buf->decoder_info[3];
      
        if(this->size) {
          audio_header = (xine_waveformatex *)this->buf;
        
          this->context->block_align = audio_header->nBlockAlign;
          this->context->bit_rate    = audio_header->nAvgBytesPerSec * 8;
      
          if(audio_header->cbSize > 0) {
            this->context->extradata = xine_xmalloc(audio_header->cbSize);
            this->context->extradata_size = audio_header->cbSize;
            memcpy( this->context->extradata, 
                    (uint8_t *)audio_header + sizeof(xine_waveformatex),
                    audio_header->cbSize ); 
          }
        }
      } else {
        short *ptr;
        
        switch(codec_type) {
          case BUF_AUDIO_14_4:
            this->audio_sample_rate = 8000;
            this->audio_channels    = 1;
          
            this->context->block_align = 240;
            break;
          case BUF_AUDIO_28_8:
            this->audio_sample_rate = BE_16(&this->buf[0x30]);
            this->audio_channels    = this->buf[0x37];
            /* this->audio_bits = buf->content[0x35] */
  
            this->context->block_align = BE_16(&this->buf[0x2A]);
  
            this->context->extradata_size = 5*sizeof(short);
            this->context->extradata      = xine_xmalloc(this->context->extradata_size);
  
            ptr = (short *) this->context->extradata;
  
            ptr[0] = BE_16(&this->buf[0x2C]); /* subpacket size */
            ptr[1] = BE_16(&this->buf[0x28]); /* subpacket height */
            ptr[2] = BE_16(&this->buf[0x16]); /* subpacket flavour */
            ptr[3] = BE_32(&this->buf[0x18]); /* coded frame size */
            ptr[4] = 0;                          /* codec's data length  */
            break;
          default:
            xprintf(this->stream->xine, XINE_VERBOSITY_LOG,
                    "ffmpeg_audio_dec: unknown header with buf type 0x%X\n", codec_type);
            break;
        }
      }
  
      /* Current ffmpeg audio decoders always use 16 bits/sample 
       * buf->decoder_info[2] can't be used as it doesn't refer to the output
       * bits/sample for some codecs (e.g. MS ADPCM) */
      this->audio_bits = 16;  
  
      this->context->sample_rate = this->audio_sample_rate;
      this->context->channels    = this->audio_channels;
      this->context->codec_id    = this->codec->id;
      this->context->codec_tag   = _x_stream_info_get(this->stream, XINE_STREAM_INFO_AUDIO_FOURCC);
  
      this->size = 0;
  
      this->decode_buffer = xine_xmalloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
  
      if (avcodec_open (this->context, this->codec) < 0) {
        xprintf (this->stream->xine, XINE_VERBOSITY_LOG, 
                 _("ffmpeg_audio_dec: couldn't open decoder\n"));
        _x_stream_info_set(this->stream, XINE_STREAM_INFO_AUDIO_HANDLED, 0);
        return;
      }
  
      this->decoder_ok = 1;
  
      return;
    }
  } else if ((buf->decoder_flags & BUF_FLAG_SPECIAL) &&
             (buf->decoder_info[1] == BUF_SPECIAL_STSD_ATOM)) {

    this->context->extradata_size = buf->decoder_info[2];
    this->context->extradata = xine_xmalloc(buf->decoder_info[2]);
    memcpy(this->context->extradata, buf->decoder_info_ptr[2],
      buf->decoder_info[2]);

  } else if (this->decoder_ok && !(buf->decoder_flags & BUF_FLAG_SPECIAL)) {

    if (!this->output_open) {
      this->output_open = this->stream->audio_out->open(this->stream->audio_out,
        this->stream, this->audio_bits, this->audio_sample_rate,
        (this->audio_channels == 2) ? AO_CAP_MODE_STEREO : AO_CAP_MODE_MONO);
    }

    /* if the audio still isn't open, bail */
    if (!this->output_open)
      return;

    if( buf->decoder_flags & BUF_FLAG_PREVIEW )
      return;

    ff_audio_ensure_buffer_size(this, this->size + buf->size);
    xine_fast_memcpy (&this->buf[this->size], buf->content, buf->size);
    this->size += buf->size;

    if (buf->decoder_flags & BUF_FLAG_FRAME_END)  { /* time to decode a frame */

      offset = 0;
      while (this->size>0) {
        bytes_consumed = avcodec_decode_audio (this->context, 
                                               (int16_t *)this->decode_buffer,
                                               &decode_buffer_size, 
                                               &this->buf[offset],
                                               this->size);

        if (bytes_consumed<0) {
          xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, 
                   "ffmpeg_audio_dec: error decompressing audio frame\n");
          this->size=0;
          return;
        } else if (bytes_consumed == 0)
          return;

        /* dispatch the decoded audio */
        out = 0;
        while (out < decode_buffer_size) {
          audio_buffer = 
            this->stream->audio_out->get_buffer (this->stream->audio_out);
          if (audio_buffer->mem_size == 0) {
            xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG, 
                     "ffmpeg_audio_dec: Help! Allocated audio buffer with nothing in it!\n");
            return;
          }

          if ((decode_buffer_size - out) > audio_buffer->mem_size)
            bytes_to_send = audio_buffer->mem_size;
          else
            bytes_to_send = decode_buffer_size - out;

          /* fill up this buffer */
          xine_fast_memcpy(audio_buffer->mem, &this->decode_buffer[out],
            bytes_to_send);
          /* byte count / 2 (bytes / sample) / channels */
          audio_buffer->num_frames = bytes_to_send / 2 / this->audio_channels;

          audio_buffer->vpts = buf->pts;
          buf->pts = 0;  /* only first buffer gets the real pts */
          this->stream->audio_out->put_buffer (this->stream->audio_out,
            audio_buffer, this->stream);

          out += bytes_to_send;
        }

        this->size -= bytes_consumed;
        offset += bytes_consumed;
      }

      /* reset internal accumulation buffer */
      this->size = 0;
    }
  }
}

static void ff_audio_reset (audio_decoder_t *this_gen) {
  ff_audio_decoder_t *this = (ff_audio_decoder_t *) this_gen;
  
  this->size = 0;

  /* try to reset the wma decoder */
  if( this->context ) {  
    avcodec_close (this->context);
    avcodec_open (this->context, this->codec);
  }
}

static void ff_audio_discontinuity (audio_decoder_t *this_gen) {
}

static void ff_audio_dispose (audio_decoder_t *this_gen) {

  ff_audio_decoder_t *this = (ff_audio_decoder_t *) this_gen;
  
  if( this->context )
    avcodec_close (this->context);

  if (this->output_open)
    this->stream->audio_out->close (this->stream->audio_out, this->stream);
  this->output_open = 0;

  free(this->buf);
  free(this->decode_buffer);

  if(this->context && this->context->extradata)
    free(this->context->extradata);

  if(this->context)
    free(this->context);

  free (this_gen);
}

static audio_decoder_t *ff_audio_open_plugin (audio_decoder_class_t *class_gen, xine_stream_t *stream) {

  ff_audio_decoder_t *this ;

  this = (ff_audio_decoder_t *) xine_xmalloc (sizeof (ff_audio_decoder_t));

  this->audio_decoder.decode_data         = ff_audio_decode_data;
  this->audio_decoder.reset               = ff_audio_reset;
  this->audio_decoder.discontinuity       = ff_audio_discontinuity;
  this->audio_decoder.dispose             = ff_audio_dispose;

  this->output_open = 0;
  this->audio_channels = 0;
  this->stream = stream;
  this->buf = NULL;
  this->size = 0;
  this->bufsize = 0;
  this->decoder_ok = 0;
  
  ff_audio_ensure_buffer_size(this, AUDIOBUFSIZE);

  return &this->audio_decoder;
}

static char *ff_audio_get_identifier (audio_decoder_class_t *this) {
  return "ffmpeg audio";
}

static char *ff_audio_get_description (audio_decoder_class_t *this) {
  return "ffmpeg based audio decoder plugin";
}

static void ff_audio_dispose_class (audio_decoder_class_t *this) {
  free (this);
}

void *init_audio_plugin (xine_t *xine, void *data) {

  ff_audio_class_t *this ;

  this = (ff_audio_class_t *) xine_xmalloc (sizeof (ff_audio_class_t));

  this->decoder_class.open_plugin     = ff_audio_open_plugin;
  this->decoder_class.get_identifier  = ff_audio_get_identifier;
  this->decoder_class.get_description = ff_audio_get_description;
  this->decoder_class.dispose         = ff_audio_dispose_class;

  pthread_once( &once_control, init_once_routine );

  return this;
}

static uint32_t supported_audio_types[] = { 
  BUF_AUDIO_WMAV1,
  BUF_AUDIO_WMAV2,
  BUF_AUDIO_14_4,
  BUF_AUDIO_28_8,
  BUF_AUDIO_MULAW,
  BUF_AUDIO_ALAW,
  BUF_AUDIO_MSADPCM,
  BUF_AUDIO_QTIMAADPCM,
  BUF_AUDIO_MSIMAADPCM,
  BUF_AUDIO_DK3ADPCM,
  BUF_AUDIO_DK4ADPCM,
  BUF_AUDIO_XA_ADPCM,
  BUF_AUDIO_ROQ,
  BUF_AUDIO_INTERPLAY,
  BUF_AUDIO_VQA_IMA,
  BUF_AUDIO_4X_ADPCM,
  BUF_AUDIO_MAC3,
  BUF_AUDIO_MAC6,
  BUF_AUDIO_XAN_DPCM,
  BUF_AUDIO_VMD,
  BUF_AUDIO_EA_ADPCM,
  BUF_AUDIO_SMJPEG_IMA,
  BUF_AUDIO_FLAC,
  /* BUF_AUDIO_MPEG, */
  0
};

decoder_info_t dec_info_ffmpeg_audio = {
  supported_audio_types,   /* supported types */
  6                        /* priority        */
};

--- NEW FILE: xine_encoder.c ---
/* 
 * Copyright (C) 2000-2004 the xine project
 * 
 * This file is part of xine, a unix 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 * $Id: xine_encoder.c,v 1.1 2005/04/04 22:29:51 dsalt-guest Exp $
 */
 
/* mpeg encoders for the dxr3 video out plugin. */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>

#define LOG_MODULE "dxr3_mpeg_encoder"
/* #define LOG_VERBOSE */
/* #define LOG */

#include "video_out_dxr3.h"

#ifdef HAVE_FFMPEG
#  include <avcodec.h>
#else
#  include "libavcodec/avcodec.h"
#endif

/* buffer size for encoded mpeg1 stream; will hold one intra frame 
 * at 640x480 typical sizes are <50 kB. 512 kB should be plenty */
#define DEFAULT_BUFFER_SIZE 512*1024


/*initialisation function*/
int         dxr3_encoder_init(dxr3_driver_t *drv);

/* functions required by encoder api */
static int lavc_on_update_format(dxr3_driver_t *drv, dxr3_frame_t *frame);
static int lavc_on_display_frame(dxr3_driver_t *drv, dxr3_frame_t *frame);
static int lavc_on_unneeded(dxr3_driver_t *drv);

/*encoder structure*/
typedef struct lavc_data_s {
  encoder_data_t     encoder_data;
  AVCodecContext     *context;         /* handle for encoding */
  int                width, height;    /* width and height of the video frame */
  uint8_t            *ffmpeg_buffer;   /* lavc buffer */
  AVFrame            *picture;         /* picture to be encoded */
  uint8_t            *out[3];          /* aligned buffer for YV12 data */
  uint8_t            *buf;             /* unaligned YV12 buffer */
} lavc_data_t;


int dxr3_encoder_init(dxr3_driver_t *drv)
{
  lavc_data_t* this;
  avcodec_init();

  register_avcodec(&mpeg1video_encoder);  
  lprintf("lavc init , version %x\n", avcodec_version());
  this = xine_xmalloc(sizeof(lavc_data_t));
  if (!this) return 0;

  this->encoder_data.type             = ENC_LAVC;
  this->encoder_data.on_update_format = lavc_on_update_format;
  this->encoder_data.on_frame_copy    = NULL;
  this->encoder_data.on_display_frame = lavc_on_display_frame;
  this->encoder_data.on_unneeded      = lavc_on_unneeded;
  this->context                       = 0;
  
  drv->enc = &this->encoder_data;
  return 1;
}

/* helper function */
static int lavc_prepare_frame(lavc_data_t *this, dxr3_driver_t *drv, dxr3_frame_t *frame);

static int lavc_on_update_format(dxr3_driver_t *drv, dxr3_frame_t *frame)
{
  lavc_data_t *this = (lavc_data_t *)drv->enc;
  AVCodec *codec;
  unsigned char use_quantizer;
  
  if (this->context) {
    avcodec_close(this->context);
    free(this->context);
    free(this->picture);
    this->context = NULL;
    this->picture = NULL;
  }
  
  /* if YUY2 and dimensions changed, we need to re-allocate the
   * internal YV12 buffer */
  if (frame->vo_frame.format == XINE_IMGFMT_YUY2) {
    int image_size = frame->vo_frame.pitches[0] * frame->oheight;

    this->out[0] = xine_xmalloc_aligned(16, image_size * 3/2, 
      (void *)&this->buf);
    this->out[1] = this->out[0] + image_size; 
    this->out[2] = this->out[1] + image_size/4; 

    /* fill with black (yuv 16,128,128) */
    memset(this->out[0], 16, image_size);
    memset(this->out[1], 128, image_size/4);
    memset(this->out[2], 128, image_size/4);
    lprintf("Using YUY2->YV12 conversion\n");  
  }
  
  /* resolution must be a multiple of two */
  if ((frame->vo_frame.pitches[0] % 2 != 0) || (frame->oheight % 2 != 0)) {
    xprintf(drv->class->xine, XINE_VERBOSITY_LOG, 
      "dxr3_mpeg_encoder: lavc only handles video dimensions which are multiples of 2\n");
    return 0;
  }

  /* get mpeg codec handle */
  codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
  if (!codec) {
    xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
      "dxr3_mpeg_encoder: lavc MPEG1 codec not found\n");
    return 0;
  }
  lprintf("lavc MPEG1 encoder found.\n");

  this->width  = frame->vo_frame.pitches[0];
  this->height = frame->oheight;

  this->context = avcodec_alloc_context();
  if (!this->context) {
    xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
      "dxr3_mpeg_encoder: Couldn't start the ffmpeg library\n");
    return 0;
  } 
  this->picture = avcodec_alloc_frame();
  if (!this->picture) {
    xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
      "dxr3_mpeg_encoder: Couldn't allocate ffmpeg frame\n");
    return 0;
  }
  
  /* put sample parameters */
  this->context->bit_rate = drv->class->xine->config->register_range(drv->class->xine->config,
    "dxr3.encoding.lavc_bitrate", 10000, 1000, 20000,
    _("libavcodec mpeg output bitrate (kbit/s)"),
    _("The bitrate the libavcodec mpeg encoder should use for DXR3's encoding mode. "
      "Higher values will increase quality and CPU usage.\n"
      "This setting is only considered, when constant quality mode is disabled."), 10, NULL, NULL);
    this->context->bit_rate *= 1000; /* config in kbit/s, libavcodec wants bit/s */
    
  use_quantizer = drv->class->xine->config->register_bool(drv->class->xine->config,
    "dxr3.encoding.lavc_quantizer", 1,
    _("constant quality mode"),
    _("When enabled, libavcodec will use a constant quality mode by dynamically "
      "compressing the images based on their complexity. When disabled, libavcodec "
      "will use constant bitrate mode."), 10, NULL, NULL);

  if (use_quantizer) {        
    this->context->qmin = drv->class->xine->config->register_range(drv->class->xine->config,
    "dxr3.encoding.lavc_qmin", 1, 1, 10,
    _("minimum compression"),
    _("The minimum compression to apply to an image in constant quality mode."),
    10, NULL, NULL);
     
    this->context->qmax = drv->class->xine->config->register_range(drv->class->xine->config,
    "dxr3.encoding.lavc_qmax", 2, 1, 20,
    _("maximum quantizer"),
    _("The maximum compression to apply to an image in constant quality mode."),
    10, NULL, NULL);  
  }

  lprintf("lavc -> bitrate %d  \n", this->context->bit_rate);

  this->context->width  = frame->vo_frame.pitches[0];
  this->context->height = frame->oheight;

  this->context->gop_size = 0; /*intra frames only */
  this->context->me_method = ME_ZERO; /*motion estimation type*/
  
  this->context->frame_rate = 90000;
  if (frame->vo_frame.duration > 90000 / 24)
    this->context->frame_rate_base = 90000 / 24;
  else if (frame->vo_frame.duration < 90000 / 60)
    this->context->frame_rate_base = 90000 / 60;
  else
    this->context->frame_rate_base = frame->vo_frame.duration;
  /* ffmpeg can complain about illegal framerates, but since this seems no
   * problem for the DXR3, we just tell ffmpeg to be more lax with */
  this->context->strict_std_compliance = -1;
  
  /* open avcodec */
  if (avcodec_open(this->context, codec) < 0) {
    xprintf(drv->class->xine, XINE_VERBOSITY_LOG, "dxr3_mpeg_encoder: could not open codec\n");
    return 0;
  }
  lprintf("dxr3_mpeg_encoder: lavc MPEG1 codec opened.\n");
  
  if (!this->ffmpeg_buffer)
    this->ffmpeg_buffer = (unsigned char *)malloc(DEFAULT_BUFFER_SIZE); /* why allocate more than needed ?! */
  if (!this->ffmpeg_buffer) {
    xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
      "dxr3_mpeg_encoder: Couldn't allocate temp buffer for mpeg data\n");
    return 0;
  }

  return 1;
}

static int lavc_on_display_frame(dxr3_driver_t *drv, dxr3_frame_t *frame)
{
  int size;
  lavc_data_t* this = (lavc_data_t *)drv->enc;
  ssize_t written;
	
  if (frame->vo_frame.bad_frame) return 1;
    /* ignore old frames */
  if ((frame->vo_frame.pitches[0] != this->context->width) || (frame->oheight != this->context->height)) {
	frame->vo_frame.free(&frame->vo_frame);
    lprintf("LAVC ignoring frame !!!\n");
    return 1;
  }

  /* prepare frame for conversion, handles YUY2 -> YV12 conversion when necessary */
  lavc_prepare_frame(this, drv, frame);

  /* do the encoding */
  size = avcodec_encode_video(this->context, this->ffmpeg_buffer, DEFAULT_BUFFER_SIZE, this->picture);

  frame->vo_frame.free(&frame->vo_frame);

  written = write(drv->fd_video, this->ffmpeg_buffer, size);
  if (written < 0) {
      xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
        "dxr3_mpeg_encoder: video device write failed (%s)\n", strerror(errno));
      return 0;
    }
  if (written != size)
      xprintf(drv->class->xine, XINE_VERBOSITY_LOG,
        "dxr3_mpeg_encoder: Could only write %d of %d mpeg bytes.\n", written, size);
  return 1;
}

static int lavc_on_unneeded(dxr3_driver_t *drv)
{
  lavc_data_t *this = (lavc_data_t *)drv->enc;
  lprintf("flushing buffers\n");
  if (this->context) {
    avcodec_close(this->context);
    free(this->context);
    free(this->picture);
    this->context = NULL;
    this->picture = NULL;
  }
  return 1;
}

static int lavc_prepare_frame(lavc_data_t *this, dxr3_driver_t *drv, dxr3_frame_t *frame)
{
  int i, j, w2;
  uint8_t *yuy2;
	
  if (frame->vo_frame.bad_frame) return 1;

  if (frame->vo_frame.format == XINE_IMGFMT_YUY2) {
    /* need YUY2->YV12 conversion */
    if (!(this->out[0] && this->out[1] && this->out[2]) ) {
      lprintf("Internal YV12 buffer not created.\n");
      return 0;
    }
    this->picture->data[0] = this->out[0] +  frame->vo_frame.pitches[0]      *  drv->top_bar;		/* y */
    this->picture->data[1] = this->out[1] + (frame->vo_frame.pitches[0] / 2) * (drv->top_bar / 2);	/* u */
    this->picture->data[2] = this->out[2] + (frame->vo_frame.pitches[0] / 2) * (drv->top_bar / 2);	/* v */
    yuy2 = frame->vo_frame.base[0];
    w2 = frame->vo_frame.pitches[0] / 2;
    for (i = 0; i < frame->vo_frame.height; i += 2) {
      for (j = 0; j < w2; j++) {
        /* packed YUV 422 is: Y[i] U[i] Y[i+1] V[i] */
        *(this->picture->data[0]++) = *(yuy2++);
        *(this->picture->data[1]++) = *(yuy2++);
        *(this->picture->data[0]++) = *(yuy2++);
        *(this->picture->data[2]++) = *(yuy2++);
      }
      /* down sampling */
      for (j = 0; j < w2; j++) {
        /* skip every second line for U and V */
        *(this->picture->data[0]++) = *(yuy2++);
        yuy2++;
        *(this->picture->data[0]++) = *(yuy2++);
        yuy2++;
      }
    }
    /* reset for encoder */
    this->picture->data[0] = this->out[0];
    this->picture->data[1] = this->out[1];
    this->picture->data[2] = this->out[2];
  }
  else { /* YV12 **/  
	this->picture->data[0] = frame->real_base[0];
    this->picture->data[1] = frame->real_base[1];
    this->picture->data[2] = frame->real_base[2];
  }
  this->picture->linesize[0] = this->context->width;
  this->picture->linesize[1] = this->context->width / 2;
  this->picture->linesize[2] = this->context->width / 2;
  return 1;
}

--- NEW FILE: xine_decoder.h ---
/*
 * Copyright (C) 2001-2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 * $Id: xine_decoder.h,v 1.1 2005/04/04 22:29:51 dsalt-guest Exp $
 *
 */
 
#ifndef HAVE_XINE_DECODER_H
#define HAVE_XINE_DECODER_H

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_FFMPEG
#  include <avcodec.h>
#else
#  include "libavcodec/avcodec.h"
#endif

#ifdef _MSC_VER
#  undef malloc
#  undef free
#  undef realloc
#  undef printf
#  undef fprintf
#endif

typedef struct ff_codec_s {
  uint32_t          type;
  enum CodecID      id;
  const char       *name;
} ff_codec_t;

void *init_audio_plugin (xine_t *xine, void *data);
void *init_video_plugin (xine_t *xine, void *data);

extern decoder_info_t dec_info_ffmpeg_video;
extern decoder_info_t dec_info_ffmpeg_wmv8;
extern decoder_info_t dec_info_ffmpeg_audio;

extern pthread_once_t once_control;
void init_once_routine(void);

#endif

--- NEW FILE: Makefile.in ---
# Makefile.in generated by automake 1.9.3 from Makefile.am.
# @configure_input@

# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004  Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.

@SET_MAKE@


SOURCES = $(xineplug_decode_dvaudio_la_SOURCES) $(xineplug_decode_ff_la_SOURCES)

[...961 lines suppressed...]

uninstall-hook:
	@if echo '$(libdir)' | egrep ^'$(XINE_PLUGINDIR)' >/dev/null; then \
	  list='$(lib_LTLIBRARIES)'; for p in $$list; do \
	    p="`echo $$p | sed -e 's/\.la$$/\.so/g;s|^.*/||'`"; \
	    echo " rm -f $(DESTDIR)$(libdir)/$$p"; \
	    rm -f $(DESTDIR)$(libdir)/$$p; \
	  done; \
	fi

mostlyclean-generic:
	-rm -f *~ \#* .*~ .\#*

maintainer-clean-generic:
	-@echo "This command is intended for maintainers to use;"
	-@echo "it deletes files that may require special tools to rebuild."
	-rm -f Makefile.in
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

--- NEW FILE: xine_decoder.c ---
/*
 * Copyright (C) 2001-2004 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 *
 * $Id: xine_decoder.c,v 1.1 2005/04/04 22:29:51 dsalt-guest Exp $
 *
 * xine decoder plugin using ffmpeg
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "xine_internal.h"

#include "xine_decoder.h"

/*
 * common initialisation
 */

pthread_once_t once_control = PTHREAD_ONCE_INIT;

void avcodec_register_all(void)
{
    static int inited = 0;
    
    if (inited != 0)
	return;
    inited = 1;

    /* decoders */
    register_avcodec(&h263_decoder);
    register_avcodec(&mpeg4_decoder);
    register_avcodec(&msmpeg4v1_decoder);
    register_avcodec(&msmpeg4v2_decoder);
    register_avcodec(&msmpeg4v3_decoder);
    register_avcodec(&wmv1_decoder);
    register_avcodec(&wmv2_decoder);
    register_avcodec(&h263i_decoder);
    register_avcodec(&rv10_decoder);
    register_avcodec(&rv20_decoder);
    register_avcodec(&svq1_decoder);
    register_avcodec(&svq3_decoder);
    register_avcodec(&wmav1_decoder);
    register_avcodec(&wmav2_decoder);
    register_avcodec(&indeo3_decoder);
    register_avcodec(&mpeg1video_decoder);
    register_avcodec(&dvvideo_decoder);
    register_avcodec(&pcm_s16le_decoder);
    register_avcodec(&mjpeg_decoder);
    register_avcodec(&mjpegb_decoder);
    register_avcodec(&mp2_decoder);
    register_avcodec(&mp3_decoder);
    register_avcodec(&mace3_decoder);
    register_avcodec(&mace6_decoder);
    register_avcodec(&huffyuv_decoder);
    register_avcodec(&cyuv_decoder);
    register_avcodec(&h264_decoder);
    register_avcodec(&vp3_decoder);
    register_avcodec(&fourxm_decoder);
    register_avcodec(&ra_144_decoder);
    register_avcodec(&ra_288_decoder);
    register_avcodec(&adpcm_ms_decoder);
    register_avcodec(&adpcm_ima_qt_decoder);
    register_avcodec(&adpcm_ima_wav_decoder);
    register_avcodec(&adpcm_ima_dk3_decoder);
    register_avcodec(&adpcm_ima_dk4_decoder);
    register_avcodec(&adpcm_ima_ws_decoder);
    register_avcodec(&adpcm_ima_smjpeg_decoder);
    register_avcodec(&adpcm_xa_decoder);
    register_avcodec(&adpcm_4xm_decoder);
    register_avcodec(&adpcm_ea_decoder);
    register_avcodec(&pcm_alaw_decoder);
    register_avcodec(&pcm_mulaw_decoder);
    register_avcodec(&roq_dpcm_decoder);
    register_avcodec(&interplay_dpcm_decoder);
    register_avcodec(&cinepak_decoder);
    register_avcodec(&msvideo1_decoder);
    register_avcodec(&msrle_decoder);
    register_avcodec(&rpza_decoder);
    register_avcodec(&roq_decoder);
    register_avcodec(&idcin_decoder);
    register_avcodec(&xan_wc3_decoder);
    register_avcodec(&vqa_decoder);
    register_avcodec(&interplay_video_decoder);
    register_avcodec(&flic_decoder);
    register_avcodec(&smc_decoder);
    register_avcodec(&eightbps_decoder);
    register_avcodec(&vmdvideo_decoder);
    register_avcodec(&vmdaudio_decoder);
    register_avcodec(&truemotion1_decoder);
    register_avcodec(&mszh_decoder);
    register_avcodec(&zlib_decoder);
    register_avcodec(&xan_dpcm_decoder);
    register_avcodec(&asv1_decoder);
    register_avcodec(&asv2_decoder);
    register_avcodec(&vcr1_decoder);
    register_avcodec(&flv_decoder);
    register_avcodec(&qtrle_decoder);
    register_avcodec(&flac_decoder);
}

void init_once_routine(void) {
  avcodec_init();
  avcodec_register_all();
}

/*
 * exported plugin catalog entry
 */

plugin_info_t xine_plugin_info[] = {
  /* type, API, "name", version, special_info, init_function */  
  { PLUGIN_VIDEO_DECODER | PLUGIN_MUST_PRELOAD, 18, "ffmpegvideo", XINE_VERSION_CODE, &dec_info_ffmpeg_video, init_video_plugin },
  { PLUGIN_VIDEO_DECODER, 18, "ffmpeg-wmv8", XINE_VERSION_CODE, &dec_info_ffmpeg_wmv8, init_video_plugin },
  { PLUGIN_AUDIO_DECODER, 15, "ffmpegaudio", XINE_VERSION_CODE, &dec_info_ffmpeg_audio, init_audio_plugin },
  { PLUGIN_NONE, 0, "", 0, NULL, NULL }
};