Commit 3f8b6306 authored by Jean-Paul Saman's avatar Jean-Paul Saman

Support for X11 Unichrome and XvMC extensions. The patch includes hw codec and...

Support for X11 Unichrome and XvMC extensions. The patch includes hw codec and video_output module for testing on VIA boards (CLE266). Patch by Christophe Burgalat <c.burgalat _at_ broadcastavenue _dot_ com>

This patch is not tested yet and is disabled by default.
parent d3217fc7
......@@ -39,6 +39,7 @@ Cédric Cocquebert - Misc opengl effects for the OpenGL Video Output. "Panoramix
Chris Clepper - OpenGL fix
Christian Henz - libupnp service discovery plugin, CyberLink UPnP fixes
Christof Baumgaertner - dbox web intf
Christophe Burgalat <c.burgalat _at_ broadcastavenue _dot_ com> - XVMC (cle266) patch for VIA boards
Christophe Mutricy <xtophe at nxtelevision dot com> - many fixes (preferences, M3U, ...)
Christopher Johnson <cjohnson at mint.net> - Qt fix in vlc.spec
Colin Simmonds <colin_simmonds at Mac.lover.org> - compile fix for Mac OS X
......
SOURCES_xvmc = \
xxmc.c \
alloc.c \
cpu_accel.c \
cpu_state.c \
decode.c \
header.c \
motion_comp.c \
motion_comp_mmx.c \
slice.c \
slice_xvmc_vld.c \
accel_xvmc.h \
attributes.h \
xxmc-config.h \
mpeg2.h \
mpeg2_internal.h \
vlc.h \
xvmc_vld.h \
$(NULL)
/*****************************************************************************
* xvmc.c : Common acceleration definitions for XvMC
*****************************************************************************
* Copyright (C) 2006 VideoLAN
* $Id$
*
* Authors: Christophe Burgalat <c _dot_ burgalat _at_ broadcastavenue _dot_ com>
* Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
*
* This program 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.
*
* This program 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, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
/*
* Common acceleration definitions for XvMC
*
*
*/
#ifndef HAVE_VLC_ACCEL_H
#define HAVE_VLC_ACCEL_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct vlc_macroblock_s
{
short *blockptr; /* pointer to current dct block */
short *blockbaseptr; /* pointer to base of dct block array in blocks */
short xvmc_accel; /* type of acceleration supported */
} vlc_macroblocks_t;
typedef struct vlc_vld_frame_s
{
int version; /* Backward compatibility */
int mv_ranges[2][2];
int picture_structure;
int picture_coding_type;
int intra_dc_precision;
int mpeg_coding;
int progressive_sequence;
int scan;
int pred_dct_frame;
int concealment_motion_vectors;
int q_scale_type;
int intra_vlc_format;
int second_field;
int load_intra_quantizer_matrix;
int load_non_intra_quantizer_matrix;
uint8_t intra_quantizer_matrix[64];
uint8_t non_intra_quantizer_matrix[64];
picture_t *backward_reference_picture;
picture_t *forward_reference_picture;
} vlc_vld_frame_t;
typedef struct vlc_xvmc_s
{
vlc_macroblocks_t *macroblocks;
void (*proc_macro_block)(int x,int y,int mb_type,
int motion_type,int (*mv_field_sel)[2],
int *dmvector,int cbp,int dct_type,
picture_t *current_picture,picture_t *forward_ref_picture,
picture_t *backward_ref_picture,int picture_structure,
int second_field,int (*f_mot_pmv)[2],int (*b_mot_pmv)[2]);
} vlc_xvmc_t ;
typedef struct vlc_xxmc_s
{
/*
* We inherit the xine_xvmc_t properties.
*/
vlc_xvmc_t xvmc;
unsigned mpeg;
unsigned acceleration;
vlc_fourcc_t fallback_format;
vlc_vld_frame_t vld_frame;
uint8_t *slice_data;
unsigned slice_data_size;
unsigned slice_code;
int result;
int decoded;
float sleep;
void (*proc_xxmc_update_frame) (picture_t *picture_gen,
uint32_t width, uint32_t height, double ratio,
int format, int flags);
void (*proc_xxmc_begin) (picture_t *vo_img);
void (*proc_xxmc_slice) (picture_t *vo_img);
void (*proc_xxmc_flush) (picture_t *vo_img);
void (*proc_xxmc_flushsync) (picture_t *vo_img);
} vlc_xxmc_t;
#define VLC_IMGFMT_XXMC VLC_FOURCC('X','x','M','C')
/*
* Register XvMC stream types here.
*/
#define VLC_XVMC_MPEG_1 0x00000001
#define VLC_XVMC_MPEG_2 0x00000002
#define VLC_XVMC_MPEG_4 0x00000004
/*
* Register XvMC acceleration levels here.
*/
#define VLC_XVMC_ACCEL_MOCOMP 0x00000001
#define VLC_XVMC_ACCEL_IDCT 0x00000002
#define VLC_XVMC_ACCEL_VLD 0x00000004
/* xvmc acceleration types */
#define VLC_VO_MOTION_ACCEL 1
#define VLC_VO_IDCT_ACCEL 2
#define VLC_VO_SIGNED_INTRA 4
/* motion types */
#define VLC_MC_FIELD 1
#define VLC_MC_FRAME 2
#define VLC_MC_16X8 2
#define VLC_MC_DMV 3
/* picture coding type */
#define VLC_PICT_I_TYPE 1
#define VLC_PICT_P_TYPE 2
#define VLC_PICT_B_TYPE 3
#define VLC_PICT_D_TYPE 4
/* macroblock modes */
#define VLC_MACROBLOCK_INTRA 1
#define VLC_MACROBLOCK_PATTERN 2
#define VLC_MACROBLOCK_MOTION_BACKWARD 4
#define VLC_MACROBLOCK_MOTION_FORWARD 8
#define VLC_MACROBLOCK_QUANT 16
#define VLC_MACROBLOCK_DCT_TYPE_INTERLACED 32
#ifdef __cplusplus
}
#endif
#endif
/* $Id:$
* alloc.c
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#include <stdlib.h>
#include <inttypes.h>
#include "mpeg2.h"
static void * (* malloc_hook) (unsigned size, mpeg2_alloc_t reason) = NULL;
static int (* free_hook) (void * buf) = NULL;
void * mpeg2_malloc( unsigned size, mpeg2_alloc_t reason )
{
char *buf = NULL;
if (malloc_hook)
{
buf = (char *) malloc_hook (size, reason);
if (buf)
return buf;
}
if (size)
{
buf = (char *) malloc (size + 63 + sizeof (void **));
if (buf)
{
char * align_buf = NULL;
align_buf = buf + 63 + sizeof (void **);
align_buf -= (long)align_buf & 63;
*(((void **)align_buf) - 1) = buf;
return align_buf;
}
}
return NULL;
}
void mpeg2_free( void * buf )
{
if (free_hook && free_hook (buf))
return;
if (buf)
free (*(((void **)buf) - 1));
}
void mpeg2_malloc_hooks( void * malloc (unsigned, mpeg2_alloc_t),
int free (void *) )
{
malloc_hook = malloc;
free_hook = free;
}
/* $Id:$
* attributes.h
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
/* use gcc attribs to align critical data structures */
#ifdef ATTRIBUTE_ALIGNED_MAX
# define ATTR_ALIGN(align) __attribute__ ((__aligned__ ((ATTRIBUTE_ALIGNED_MAX < align) ? ATTRIBUTE_ALIGNED_MAX : align)))
#else
# define ATTR_ALIGN(align)
#endif
#ifdef HAVE_BUILTIN_EXPECT
# define likely(x) __builtin_expect ((x) != 0, 1)
# define unlikely(x) __builtin_expect ((x) != 0, 0)
#else
# define likely(x) (x)
# define unlikely(x) (x)
#endif
/* $Id:$
* cpu_accel.c
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#include <inttypes.h>
#include "mpeg2.h"
#include "attributes.h"
#include "mpeg2_internal.h"
static inline uint32_t arch_accel( void )
{
uint32_t eax, ebx, ecx, edx;
int AMD;
uint32_t caps;
#if !defined(PIC) && !defined(__PIC__)
#define cpuid(op,eax,ebx,ecx,edx) \
__asm__ ("cpuid" \
: "=a" (eax), \
"=b" (ebx), \
"=c" (ecx), \
"=d" (edx) \
: "a" (op) \
: "cc")
#else /* PIC version : save ebx */
#define cpuid(op,eax,ebx,ecx,edx) \
__asm__ ("push %%ebx\n\t" \
"cpuid\n\t" \
"movl %%ebx,%1\n\t" \
"pop %%ebx" \
: "=a" (eax), \
"=r" (ebx), \
"=c" (ecx), \
"=d" (edx) \
: "a" (op) \
: "cc")
#endif
__asm__ ("pushf\n\t"
"pushf\n\t"
"pop %0\n\t"
"movl %0,%1\n\t"
"xorl $0x200000,%0\n\t"
"push %0\n\t"
"popf\n\t"
"pushf\n\t"
"pop %0\n\t"
"popf"
: "=r" (eax),
"=r" (ebx)
:
: "cc");
if (eax == ebx) /* no cpuid */
return 0;
cpuid (0x00000000, eax, ebx, ecx, edx);
if (!eax) /* vendor string only */
return 0;
AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65);
cpuid (0x00000001, eax, ebx, ecx, edx);
if (! (edx & 0x00800000)) /* no MMX */
return 0;
caps = MPEG2_ACCEL_X86_MMX;
if (edx & 0x02000000) /* SSE - identical to AMD MMX extensions */
caps = MPEG2_ACCEL_X86_MMX | MPEG2_ACCEL_X86_MMXEXT;
cpuid (0x80000000, eax, ebx, ecx, edx);
if (eax < 0x80000001) /* no extended capabilities */
return caps;
cpuid (0x80000001, eax, ebx, ecx, edx);
if (edx & 0x80000000)
caps |= MPEG2_ACCEL_X86_3DNOW;
if (AMD && (edx & 0x00400000)) /* AMD MMX extensions */
caps |= MPEG2_ACCEL_X86_MMXEXT;
return caps;
}
uint32_t mpeg2_detect_accel (void)
{
uint32_t accel;
accel = 0;
accel = arch_accel ();
return accel;
}
/* $Id:$
* cpu_state.c
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#include "xxmc-config.h"
#include <stdlib.h>
#include <inttypes.h>
#include "mpeg2.h"
#include "attributes.h"
#include "mpeg2_internal.h"
#ifdef ARCH_X86
# include "mmx.h"
#endif
void (* mpeg2_cpu_state_save) (cpu_state_t * state) = NULL;
void (* mpeg2_cpu_state_restore) (cpu_state_t * state) = NULL;
static void state_restore_mmx (cpu_state_t * state)
{
emms ();
}
void mpeg2_cpu_state_init (uint32_t accel)
{
if (accel & MPEG2_ACCEL_X86_MMX)
{
mpeg2_cpu_state_restore = state_restore_mmx;
}
}
/* $Id:$
* decode.c
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#include "xxmc-config.h"
#include <string.h> /* memcmp/memset, try to remove */
#include <stdlib.h>
#include <inttypes.h>
#include "mpeg2.h"
#include "attributes.h"
#include "mpeg2_internal.h"
static int mpeg2_accels = 0;
#define BUFFER_SIZE (1194 * 1024)
const mpeg2_info_t *mpeg2_info( mpeg2dec_t * mpeg2dec )
{
return &(mpeg2dec->info);
}
static inline int skip_chunk( mpeg2dec_t * mpeg2dec, int bytes )
{
uint8_t *current = NULL;
uint32_t shift;
uint8_t *limit = NULL;
uint8_t byte;
if (!bytes)
return 0;
current = mpeg2dec->buf_start;
shift = mpeg2dec->shift;
limit = current + bytes;
do {
byte = *current++;
if (shift == 0x00000100)
{
int skipped;
mpeg2dec->shift = 0xffffff00;
skipped = current - mpeg2dec->buf_start;
mpeg2dec->buf_start = current;
return skipped;
}
shift = (shift | byte) << 8;
} while (current < limit);
mpeg2dec->shift = shift;
mpeg2dec->buf_start = current;
return 0;
}
static inline int copy_chunk( mpeg2dec_t * mpeg2dec, int bytes )
{
uint8_t *current = NULL;
uint32_t shift;
uint8_t *chunk_ptr = NULL;
uint8_t *limit = NULL;
uint8_t byte;
if (!bytes)
return 0;
current = mpeg2dec->buf_start;
shift = mpeg2dec->shift;
chunk_ptr = mpeg2dec->chunk_ptr;
limit = current + bytes;
do {
byte = *current++;
if (shift == 0x00000100)
{
int copied;
mpeg2dec->shift = 0xffffff00;
mpeg2dec->chunk_size = chunk_ptr - mpeg2dec->chunk_start - 3;
mpeg2dec->chunk_ptr = chunk_ptr + 1;
copied = current - mpeg2dec->buf_start;
mpeg2dec->buf_start = current;
return copied;
}
shift = (shift | byte) << 8;
*chunk_ptr++ = byte;
} while (current < limit);
mpeg2dec->shift = shift;
mpeg2dec->buf_start = current;
return 0;
}
void mpeg2_buffer( mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end )
{
mpeg2dec->buf_start = start;
mpeg2dec->buf_end = end;
}
int mpeg2_getpos( mpeg2dec_t * mpeg2dec )
{
return mpeg2dec->buf_end - mpeg2dec->buf_start;
}
static inline mpeg2_state_t seek_chunk( mpeg2dec_t * mpeg2dec )
{
int size, skipped;
size = mpeg2dec->buf_end - mpeg2dec->buf_start;
skipped = skip_chunk (mpeg2dec, size);
if (!skipped)
{
mpeg2dec->bytes_since_tag += size;
return STATE_BUFFER;
}
mpeg2dec->bytes_since_tag += skipped;
mpeg2dec->code = mpeg2dec->buf_start[-1];
return (mpeg2_state_t)-1;
}
mpeg2_state_t mpeg2_seek_header( mpeg2dec_t * mpeg2dec )
{
while( (mpeg2dec->code != 0xb3) &&
(((mpeg2dec->code != 0xb7) &&
(mpeg2dec->code != 0xb8) &&
mpeg2dec->code ) ||
(mpeg2dec->sequence.width == (unsigned)-1)) )
{
if (seek_chunk (mpeg2dec) == STATE_BUFFER)
return STATE_BUFFER;
}
mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
mpeg2dec->user_data_len = 0;
return (mpeg2dec->code ? mpeg2_parse_header (mpeg2dec) :
mpeg2_header_picture_start (mpeg2dec));
}
#define RECEIVED(code,state) (((state) << 8) + (code))
mpeg2_state_t mpeg2_parse( mpeg2dec_t * mpeg2dec )
{
int size_buffer, size_chunk, copied;
if (mpeg2dec->action)
{
mpeg2_state_t state;
state = mpeg2dec->action (mpeg2dec);
if ((int)state >= 0)
return state;
}
while(1)
{
while( (unsignedint) (mpeg2dec->code - mpeg2dec->first_decode_slice)
< mpeg2dec->nb_decode_slices )
{
size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start;
size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE -
mpeg2dec->chunk_ptr);
if (size_buffer <= size_chunk)
{
copied = copy_chunk (mpeg2dec, size_buffer);
if (!copied)
{
mpeg2dec->bytes_since_tag += size_buffer;
mpeg2dec->chunk_ptr += size_buffer;
return STATE_BUFFER;
}
}
else
{
copied = copy_chunk (mpeg2dec, size_chunk);
if( !copied )
{
/* filled the chunk buffer without finding a start code */
mpeg2dec->bytes_since_tag += size_chunk;
mpeg2dec->action = seek_chunk;
return STATE_INVALID;
}
}
mpeg2dec->bytes_since_tag += copied;
mpeg2_xxmc_slice( &(mpeg2dec->decoder), NULL,
mpeg2dec->code,mpeg2dec->chunk_start,
mpeg2dec->chunk_size);
mpeg2dec->prev_code = mpeg2dec->code;
mpeg2dec->code = mpeg2dec->buf_start[-1];
mpeg2dec->chunk_ptr = mpeg2dec->chunk_start;
}
if( (unsigned int) (mpeg2dec->code - 1) >= (0xb0 - 1) )
break;
if( seek_chunk (mpeg2dec) == STATE_BUFFER )
return STATE_BUFFER;
}
switch( mpeg2dec->code )
{
case 0x00:
mpeg2dec->action = mpeg2_header_picture_start;
return mpeg2dec->state;
case 0xb7:
mpeg2dec->action = mpeg2_header_end;
break;
case 0xb3:
case 0xb8:
mpeg2dec->action = mpeg2_parse_header;
break;
default:
mpeg2dec->action = seek_chunk;
return STATE_INVALID;
}
return (mpeg2dec->state == STATE_SLICE) ? STATE_SLICE : STATE_INVALID;
}
mpeg2_state_t mpeg2_parse_header( mpeg2dec_t * mpeg2dec )
{
static int (* process_header[]) (mpeg2dec_t * mpeg2dec) =
{
mpeg2_header_picture,
mpeg2_header_extension,
mpeg2_header_user_data,
mpeg2_header_sequence,
NULL,
NULL,
NULL,
NULL,
mpeg2_header_gop
};
int size_buffer, size_chunk, copied;
mpeg2dec->action = mpeg2_parse_header;
mpeg2dec->info.user_data = NULL;
mpeg2dec->info.user_data_len = 0;
while( 1 )
{
size_buffer = mpeg2dec->buf_end - mpeg2dec->buf_start;
size_chunk = (mpeg2dec->chunk_buffer + BUFFER_SIZE -
mpeg2dec->chunk_ptr);
if( size_buffer <= size_chunk )
{
copied = copy_chunk (mpeg2dec, size_buffer);
if( !copied )
{
mpeg2dec->bytes_since_tag += size_buffer;
mpeg2dec->chunk_ptr += size_buffer;
return STATE_BUFFER;
}
}
else
{
copied = copy_chunk (mpeg2dec, size_chunk);
if( !copied )
{
/* filled the chunk buffer without finding a start code */
mpeg2dec->bytes_since_tag += size_chunk;
mpeg2dec->code = 0xb4;
mpeg2dec->action = mpeg2_seek_header;
return STATE_INVALID;
}
}
mpeg2dec->bytes_since_tag += copied;
if( process_header[mpeg2dec->code & 0x0b](mpeg2dec) )
{
mpeg2dec->code = mpeg2dec->buf_start[-1];
mpeg2dec->action = mpeg2_seek_header;
return STATE_INVALID;
}
mpeg2dec->code = mpeg2dec->buf_start[-1];
switch( RECEIVED(mpeg2dec->code, mpeg2dec->state) )
{
/* state transition after a sequence header */
case RECEIVED (0x00, STATE_SEQUENCE):
mpeg2dec->action = mpeg2_header_picture_start;
case RECEIVED (0xb8, STATE_SEQUENCE):
mpeg2_header_sequence_finalize( mpeg2dec );
break;
/* other legal state transitions */
case RECEIVED (0x00, STATE_GOP):
mpeg2_header_gop_finalize( mpeg2dec );
mpeg2dec->action = mpeg2_header_picture_start;
break;
case RECEIVED (0x01, STATE_PICTURE):
case RECEIVED (0x01, STATE_PICTURE_2ND):
mpeg2_header_picture_finalize( mpeg2dec, mpeg2_accels );
mpeg2dec->action = mpeg2_header_slice_start;
break;
/* legal headers within a given state */
case RECEIVED (0xb2, STATE_SEQUENCE):
case RECEIVED (0xb2, STATE_GOP):
case RECEIVED (0xb2, STATE_PICTURE):
case RECEIVED (0xb2, STATE_PICTURE_2ND):
case RECEIVED (0xb5, STATE_SEQUENCE):
case RECEIVED (0xb5, STATE_PICTURE):
case RECEIVED (0xb5, STATE_PICTURE_2ND):
mpeg2dec->chunk_ptr = mpeg2dec->chunk_start;
continue;
default:
mpeg2dec->action = mpeg2_seek_header;
return STATE_INVALID;
}
mpeg2dec->chunk_start = mpeg2dec->chunk_ptr = mpeg2dec->chunk_buffer;
mpeg2dec->user_data_len = 0;
return mpeg2dec->state;
}
}
int mpeg2_convert( mpeg2dec_t * mpeg2dec, mpeg2_convert_t convert, void * arg )
{
mpeg2_convert_init_t convert_init;
int error;
error = convert( MPEG2_CONVERT_SET, NULL, &(mpeg2dec->sequence), 0,
mpeg2_accels, arg, &convert_init );
if (!error)
{
mpeg2dec->convert = convert;
mpeg2dec->convert_arg = arg;
mpeg2dec->convert_id_size = convert_init.id_size;
mpeg2dec->convert_stride = 0;
}
return error;
}
int mpeg2_stride( mpeg2dec_t * mpeg2dec, int stride )
{
if (!mpeg2dec->convert)
{
if (stride < (int) mpeg2dec->sequence.width)
stride = mpeg2dec->sequence.width;
mpeg2dec->decoder.stride_frame = stride;
}
else
{
mpeg2_convert_init_t convert_init;
stride = mpeg2dec->convert( MPEG2_CONVERT_STRIDE, NULL,
&(mpeg2dec->sequence), stride,
mpeg2_accels, mpeg2dec->convert_arg,
&convert_init );
mpeg2dec->convert_id_size = convert_init.id_size;
mpeg2dec->convert_stride = stride;
}
return stride;
}
void mpeg2_set_buf( mpeg2dec_t * mpeg2dec, uint8_t * buf[3], void * id )
{
mpeg2_fbuf_t * fbuf;
if (mpeg2dec->custom_fbuf)
{
if (mpeg2dec->state == STATE_SEQUENCE)
{
mpeg2dec->fbuf[2] = mpeg2dec->fbuf[1];
mpeg2dec->fbuf[1] = mpeg2dec->fbuf[0];
}
mpeg2_set_fbuf( mpeg2dec,
(mpeg2dec->decoder.coding_type == PIC_FLAG_CODING_TYPE_B) );
fbuf = mpeg2dec->fbuf[0];
}
else
{
fbuf = &(mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index].fbuf);
mpeg2dec->alloc_index_user = ++mpeg2dec->alloc_index;
}
fbuf->buf[0] = buf[0];
fbuf->buf[1] = buf[1];
fbuf->buf[2] = buf[2];
fbuf->id = id;
}
void mpeg2_custom_fbuf( mpeg2dec_t * mpeg2dec, int custom_fbuf )
{
mpeg2dec->custom_fbuf = custom_fbuf;
}
void mpeg2_skip( mpeg2dec_t * mpeg2dec, int skip )
{
mpeg2dec->first_decode_slice = 1;
mpeg2dec->nb_decode_slices = skip ? 0 : (0xb0 - 1);
}
void mpeg2_slice_region( mpeg2dec_t * mpeg2dec, int start, int end )
{
start = (start < 1) ? 1 : (start > 0xb0) ? 0xb0 : start;
end = (end < start) ? start : (end > 0xb0) ? 0xb0 : end;
mpeg2dec->first_decode_slice = start;
mpeg2dec->nb_decode_slices = end - start;
}
void mpeg2_tag_picture( mpeg2dec_t * mpeg2dec, uint32_t tag, uint32_t tag2 )
{
mpeg2dec->tag_previous = mpeg2dec->tag_current;
mpeg2dec->tag2_previous = mpeg2dec->tag2_current;
mpeg2dec->tag_current = tag;
mpeg2dec->tag2_current = tag2;
mpeg2dec->num_tags++;
mpeg2dec->bytes_since_tag = 0;
}
uint32_t mpeg2_accel( uint32_t accel )
{
if( !mpeg2_accels )
{
if( accel & MPEG2_ACCEL_DETECT )
accel |= mpeg2_detect_accel ();
mpeg2_accels = accel |= MPEG2_ACCEL_DETECT;
mpeg2_cpu_state_init (accel);
/* mpeg2_idct_init (accel); */
mpeg2_mc_init (accel);
}
return mpeg2_accels & ~MPEG2_ACCEL_DETECT;
}
void mpeg2_reset( mpeg2dec_t * mpeg2dec, int full_reset )
{
mpeg2dec->buf_start = mpeg2dec->buf_end = NULL;
mpeg2dec->num_tags = 0;
mpeg2dec->shift = 0xffffff00;
mpeg2dec->code = 0xb4;
mpeg2dec->action = mpeg2_seek_header;
mpeg2dec->state = STATE_INVALID;
mpeg2dec->first = 1;
mpeg2dec->ptr_forward_ref_picture = NULL;
mpeg2dec->ptr_backward_ref_picture = NULL;
mpeg2_reset_info(&(mpeg2dec->info));
mpeg2dec->info.gop = NULL;
mpeg2dec->info.user_data = NULL;
mpeg2dec->info.user_data_len = 0;
if( full_reset )
{
mpeg2dec->info.sequence = NULL;
mpeg2_header_state_init (mpeg2dec);
}
}
mpeg2dec_t *mpeg2_init( void )
{
mpeg2dec_t *mpeg2dec = NULL;
mpeg2_accel( MPEG2_ACCEL_DETECT );
mpeg2dec = (mpeg2dec_t *) mpeg2_malloc( sizeof (mpeg2dec_t),
MPEG2_ALLOC_MPEG2DEC );
if( mpeg2dec == NULL )
return NULL;
memset( mpeg2dec->decoder.DCTblock, 0, 64 * sizeof (int16_t) );
memset( mpeg2dec->quantizer_matrix, 0, 4 * 64 * sizeof (uint8_t) );
mpeg2dec->chunk_buffer = (uint8_t *) mpeg2_malloc( BUFFER_SIZE + 4,
MPEG2_ALLOC_CHUNK );
mpeg2dec->sequence.width = (unsigned int)-1;
mpeg2_reset (mpeg2dec, 1);
return mpeg2dec;
}
void mpeg2_close( mpeg2dec_t * mpeg2dec )
{
mpeg2_header_state_init( mpeg2dec );
mpeg2_free( mpeg2dec->chunk_buffer );
mpeg2_free( mpeg2dec );
}
/* $Id:$
* header.c
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 2003 Regis Duchesne <hpreg@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#include "xxmc-config.h"
#include <inttypes.h>
#include <stdlib.h> /* defines NULL */
#include <string.h> /* memcmp */
#include "mpeg2.h"
#include "attributes.h"
#include "mpeg2_internal.h"
#define SEQ_EXT 2
#define SEQ_DISPLAY_EXT 4
#define QUANT_MATRIX_EXT 8
#define COPYRIGHT_EXT 0x10
#define PIC_DISPLAY_EXT 0x80
#define PIC_CODING_EXT 0x100
/* default intra quant matrix, in zig-zag order */
static const uint8_t default_intra_quantizer_matrix[64] ATTR_ALIGN(16) =
{
8,
16, 16,
19, 16, 19,
22, 22, 22, 22,
22, 22, 26, 24, 26,
27, 27, 27, 26, 26, 26,
26, 27, 27, 27, 29, 29, 29,
34, 34, 34, 29, 29, 29, 27, 27,
29, 29, 32, 32, 34, 34, 37,
38, 37, 35, 35, 34, 35,
38, 38, 40, 40, 40,
48, 48, 46, 46,
56, 56, 58,
69, 69,
83
};
uint8_t mpeg2_scan_norm[64] ATTR_ALIGN(16) =
{
/* Zig-Zag scan pattern */
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
};
uint8_t mpeg2_scan_alt[64] ATTR_ALIGN(16) =
{
/* Alternate scan pattern */
0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49,
41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43,
51, 59, 20, 28, 5, 13, 6, 14, 21, 29, 36, 44, 52, 60, 37, 45,
53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63
};
void mpeg2_header_state_init( mpeg2dec_t *mpeg2dec )
{
if( mpeg2dec->sequence.width != (unsigned int)-1 )
{
int i;
mpeg2dec->sequence.width = (unsigned int)-1;
if( !mpeg2dec->custom_fbuf )
{
for( i = mpeg2dec->alloc_index_user;
i < mpeg2dec->alloc_index; i++ )
{
mpeg2_free( mpeg2dec->fbuf_alloc[i].fbuf.buf[0] );
mpeg2_free( mpeg2dec->fbuf_alloc[i].fbuf.buf[1] );
mpeg2_free( mpeg2dec->fbuf_alloc[i].fbuf.buf[2] );
}
}
if( mpeg2dec->convert_start )
{
for( i = 0; i < 3; i++ )
{
mpeg2_free( mpeg2dec->yuv_buf[i][0] );
mpeg2_free( mpeg2dec->yuv_buf[i][1] );
mpeg2_free( mpeg2dec->yuv_buf[i][2] );
}
}
if( mpeg2dec->decoder.convert_id )
mpeg2_free( mpeg2dec->decoder.convert_id );
}
mpeg2dec->decoder.coding_type = I_TYPE;
mpeg2dec->decoder.convert = NULL;
mpeg2dec->decoder.convert_id = NULL;
mpeg2dec->decoder.load_intra_quantizer_matrix = 1;
mpeg2dec->decoder.load_non_intra_quantizer_matrix = 1;
mpeg2dec->picture = mpeg2dec->pictures;
mpeg2dec->fbuf[0] = &mpeg2dec->fbuf_alloc[0].fbuf;
mpeg2dec->fbuf[1] = &mpeg2dec->fbuf_alloc[1].fbuf;
mpeg2dec->fbuf[2] = &mpeg2dec->fbuf_alloc[2].fbuf;
mpeg2dec->first = 1;
mpeg2dec->alloc_index = 0;
mpeg2dec->alloc_index_user = 0;
mpeg2dec->first_decode_slice = 1;
mpeg2dec->nb_decode_slices = 0xb0 - 1;
mpeg2dec->convert = NULL;
mpeg2dec->convert_start = NULL;
mpeg2dec->custom_fbuf = 0;
mpeg2dec->yuv_index = 0;
}
void mpeg2_reset_info( mpeg2_info_t * info )
{
info->current_picture = info->current_picture_2nd = NULL;
info->display_picture = info->display_picture_2nd = NULL;
info->current_fbuf = info->display_fbuf = info->discard_fbuf = NULL;
}
static void info_user_data( mpeg2dec_t * mpeg2dec )
{
if( mpeg2dec->user_data_len )
{
mpeg2dec->info.user_data = mpeg2dec->chunk_buffer;
mpeg2dec->info.user_data_len = mpeg2dec->user_data_len - 3;
}
}
int mpeg2_header_sequence( mpeg2dec_t * mpeg2dec )
{
uint8_t * buffer = mpeg2dec->chunk_start;
mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
static unsigned int frame_period[16] =
{
0, 1126125, 1125000, 1080000, 900900, 900000, 540000, 450450, 450000,
/* unofficial: xing 15 fps */
1800000,
/* unofficial: libmpeg3 "Unofficial economy rates" 5/10/12/15 fps */
5400000, 2700000, 2250000, 1800000, 0, 0
};
int i;
if( (buffer[6] & 0x20) != 0x20 )/* missing marker_bit */
return 1;
i = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
if( !(sequence->display_width = sequence->picture_width = i >> 12) )
return 1;
if( !(sequence->display_height = sequence->picture_height = i & 0xfff) )
return 1;
sequence->width = (sequence->picture_width + 15) & ~15;
sequence->height = (sequence->picture_height + 15) & ~15;
sequence->chroma_width = sequence->width >> 1;
sequence->chroma_height = sequence->height >> 1;
sequence->flags = (SEQ_FLAG_PROGRESSIVE_SEQUENCE |
SEQ_VIDEO_FORMAT_UNSPECIFIED);
sequence->aspect_ratio_information = buffer[3] >> 4;
sequence->pixel_width = sequence->aspect_ratio_information; /* aspect ratio */
sequence->frame_period = frame_period[buffer[3] & 15];
sequence->byte_rate = (buffer[4]<<10) | (buffer[5]<<2) | (buffer[6]>>6);
sequence->vbv_buffer_size = ((buffer[6]<<16)|(buffer[7]<<8))&0x1ff800;
if( buffer[7] & 4 )
sequence->flags |= SEQ_FLAG_CONSTRAINED_PARAMETERS;
mpeg2dec->copy_matrix = 3;
if( buffer[7] & 2 )
{
for( i = 0; i < 64; i++ )
mpeg2dec->new_quantizer_matrix[0][mpeg2_scan_norm[i]] =
(buffer[i+7] << 7) | (buffer[i+8] >> 1);
buffer += 64;
}
else
{
for( i = 0; i < 64; i++ )
mpeg2dec->new_quantizer_matrix[0][mpeg2_scan_norm[i]] =
default_intra_quantizer_matrix[i];
}
if( buffer[7] & 1 )
{
for( i = 0; i < 64; i++ )
mpeg2dec->new_quantizer_matrix[1][mpeg2_scan_norm[i]] =
buffer[i+8];
}
else
memset( mpeg2dec->new_quantizer_matrix[1], 16, 64 );
mpeg2dec->decoder.load_intra_quantizer_matrix = 1;
mpeg2dec->decoder.load_non_intra_quantizer_matrix = 1;
sequence->profile_level_id = 0x80;
sequence->colour_primaries = 0;
sequence->transfer_characteristics = 0;
sequence->matrix_coefficients = 0;
mpeg2dec->ext_state = SEQ_EXT;
mpeg2dec->state = STATE_SEQUENCE;
mpeg2dec->display_offset_x = mpeg2dec->display_offset_y = 0;
mpeg2dec->ptr_forward_ref_picture = NULL;
mpeg2dec->ptr_backward_ref_picture = NULL;
return 0;
}
static int sequence_ext( mpeg2dec_t * mpeg2dec )
{
uint8_t * buffer = mpeg2dec->chunk_start;
mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
uint32_t flags;
if( !(buffer[3] & 1) )
return 1;
sequence->profile_level_id = (buffer[0] << 4) | (buffer[1] >> 4);
sequence->display_width = sequence->picture_width +=
((buffer[1] << 13) | (buffer[2] << 5)) & 0x3000;
sequence->display_height = sequence->picture_height +=
(buffer[2] << 7) & 0x3000;
sequence->width = (sequence->picture_width + 15) & ~15;
sequence->height = (sequence->picture_height + 15) & ~15;
flags = sequence->flags | SEQ_FLAG_MPEG2;
if( !(buffer[1] & 8) )
{
flags &= ~SEQ_FLAG_PROGRESSIVE_SEQUENCE;
sequence->height = (sequence->height + 31) & ~31;
}
if( buffer[5] & 0x80 )
flags |= SEQ_FLAG_LOW_DELAY;
sequence->flags = flags;
sequence->chroma_width = sequence->width;
sequence->chroma_height = sequence->height;
switch( buffer[1] & 6 )
{
case 0: /* invalid */
return 1;
case 2: /* 4:2:0 */
sequence->chroma_height >>= 1;
case 4: /* 4:2:2 */
sequence->chroma_width >>= 1;
}
sequence->byte_rate += ((buffer[2]<<25) | (buffer[3]<<17)) & 0x3ffc0000;
sequence->vbv_buffer_size |= buffer[4] << 21;
sequence->frame_period = sequence->frame_period *
((buffer[5]&31)+1) / (((buffer[5]>>2)&3)+1);
mpeg2dec->ext_state = SEQ_DISPLAY_EXT;
return 0;
}
static int sequence_display_ext( mpeg2dec_t * mpeg2dec )
{
uint8_t * buffer = mpeg2dec->chunk_start;
mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
uint32_t flags;
flags = ((sequence->flags & ~SEQ_MASK_VIDEO_FORMAT) |
((buffer[0]<<4) & SEQ_MASK_VIDEO_FORMAT));
if( buffer[0] & 1 )
{
flags |= SEQ_FLAG_COLOUR_DESCRIPTION;
sequence->colour_primaries = buffer[1];
sequence->transfer_characteristics = buffer[2];
sequence->matrix_coefficients = buffer[3];
buffer += 3;
}
if( !(buffer[2] & 2) )/* missing marker_bit */
return 1;
sequence->display_width = (buffer[1] << 6) | (buffer[2] >> 2);
sequence->display_height =
((buffer[2]& 1 ) << 13) | (buffer[3] << 5) | (buffer[4] >> 3);
return 0;
}
static inline void finalize_sequence( mpeg2_sequence_t * sequence )
{
int width;
int height;
sequence->byte_rate *= 50;
if( sequence->flags & SEQ_FLAG_MPEG2 )
{
switch( sequence->pixel_width )
{
case 1: /* square pixels */
sequence->pixel_width = sequence->pixel_height = 1;
return;
case 2: /* 4:3 aspect ratio */
width = 4; height = 3;
break;
case 3: /* 16:9 aspect ratio */
width = 16; height = 9;
break;
case 4: /* 2.21:1 aspect ratio */
width = 221; height = 100;
break;
default: /* illegal */
sequence->pixel_width = sequence->pixel_height = 0;
return;
}
width *= sequence->display_height;
height *= sequence->display_width;
}
else
{
if( sequence->byte_rate == 50 * 0x3ffff )
sequence->byte_rate = 0; /* mpeg-1 VBR */
switch( sequence->pixel_width )
{
case 0:
case 15: /* illegal */
sequence->pixel_width = sequence->pixel_height = 0;
return;
case 1: /* square pixels */
sequence->pixel_width = sequence->pixel_height = 1;
return;
case 3: /* 720x576 16:9 */
sequence->pixel_width = 64; sequence->pixel_height = 45;
return;
case 6: /* 720x480 16:9 */
sequence->pixel_width = 32; sequence->pixel_height = 27;
return;
case 12: /* 720*480 4:3 */
sequence->pixel_width = 8; sequence->pixel_height = 9;
return;
default:
height = 88 * sequence->pixel_width + 1171;
width = 2000;
}
}
sequence->pixel_width = width;
sequence->pixel_height = height;
while (width)
{ /* find greatest common divisor */
int tmp = width;
width = height % tmp;
height = tmp;
}
sequence->pixel_width /= height;
sequence->pixel_height /= height;
}
static void copy_matrix( mpeg2dec_t * mpeg2dec, int index )
{
if( memcmp( mpeg2dec->quantizer_matrix[index],
mpeg2dec->new_quantizer_matrix[index], 64) )
{
memcpy( mpeg2dec->quantizer_matrix[index],
mpeg2dec->new_quantizer_matrix[index], 64);
mpeg2dec->scaled[index] = -1;
}
}
static void finalize_matrix( mpeg2dec_t * mpeg2dec )
{
mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
int i;
for( i = 0; i < 2; i++ )
{
if( mpeg2dec->copy_matrix & (1 << i) )
copy_matrix (mpeg2dec, i);
if( (mpeg2dec->copy_matrix & (4 << i)) &&
memcmp( mpeg2dec->quantizer_matrix[i],
mpeg2dec->new_quantizer_matrix[i+2], 64) )
{
copy_matrix (mpeg2dec, i + 2);
decoder->chroma_quantizer[i] = decoder->quantizer_prescale[i+2];
}
else if( mpeg2dec->copy_matrix & (5 << i) )
decoder->chroma_quantizer[i] = decoder->quantizer_prescale[i];
}
#if 0
decoder->load_intra_quantizer_matrix = 1;
decoder->load_non_intra_quantizer_matrix = 1;
#endif
}
static mpeg2_state_t invalid_end_action( mpeg2dec_t * mpeg2dec )
{
mpeg2_reset_info( &(mpeg2dec->info) );
mpeg2dec->info.gop = NULL;
info_user_data( mpeg2dec );
mpeg2_header_state_init( mpeg2dec );
mpeg2dec->sequence = mpeg2dec->new_sequence;
mpeg2dec->action = mpeg2_seek_header;
mpeg2dec->state = STATE_SEQUENCE;
return STATE_SEQUENCE;
}
void mpeg2_header_sequence_finalize (mpeg2dec_t * mpeg2dec)
{
mpeg2_sequence_t * sequence = &(mpeg2dec->new_sequence);
mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
finalize_sequence (sequence);
finalize_matrix (mpeg2dec);
decoder->mpeg1 = !(sequence->flags & SEQ_FLAG_MPEG2);
decoder->progressive_sequence = (sequence->flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE);
decoder->aspect_ratio_information = sequence->aspect_ratio_information;
decoder->width = sequence->width;
decoder->height = sequence->height;
decoder->vertical_position_extension = (sequence->picture_height > 2800);
decoder->chroma_format = ((sequence->chroma_width == sequence->width) +
(sequence->chroma_height == sequence->height));
if( mpeg2dec->sequence.width != (unsigned int)-1 )
{
unsigned int new_byte_rate;
/*
* According to 6.1.1.6, repeat sequence headers should be
* identical to the original. However some DVDs dont respect
* that and have different bitrates in the repeat sequence
* headers. So we'll ignore that in the comparison and still
* consider these as repeat sequence headers.
*
* However, be careful not to alter the current sequence when
* returning STATE_INVALID_END.
*/
new_byte_rate = sequence->byte_rate;
sequence->byte_rate = mpeg2dec->sequence.byte_rate;
if( memcmp( &(mpeg2dec->sequence), sequence,
sizeof (mpeg2_sequence_t)) )
{
decoder->stride_frame = sequence->width;
sequence->byte_rate = new_byte_rate;
mpeg2_header_end( mpeg2dec );
mpeg2dec->action = invalid_end_action;
mpeg2dec->state = STATE_INVALID_END;
return;
}
sequence->byte_rate = new_byte_rate;
mpeg2dec->state = STATE_SEQUENCE_REPEATED;
}
else
decoder->stride_frame = sequence->width;
mpeg2dec->sequence = *sequence;
mpeg2_reset_info( &(mpeg2dec->info) );
mpeg2dec->info.sequence = &(mpeg2dec->sequence);
mpeg2dec->info.gop = NULL;
info_user_data( mpeg2dec );
}
int mpeg2_header_gop( mpeg2dec_t * mpeg2dec )
{
uint8_t * buffer = mpeg2dec->chunk_start;
mpeg2_gop_t * gop = &(mpeg2dec->new_gop);
if( ! (buffer[1] & 8) )
return 1;
gop->hours = (buffer[0] >> 2) & 31;
gop->minutes = ((buffer[0] << 4) | (buffer[1] >> 4)) & 63;
gop->seconds = ((buffer[1] << 3) | (buffer[2] >> 5)) & 63;
gop->pictures = ((buffer[2] << 1) | (buffer[3] >> 7)) & 63;
gop->flags = (buffer[0] >> 7) | ((buffer[3] >> 4) & 6);
mpeg2dec->state = STATE_GOP;
return 0;
}
void mpeg2_header_gop_finalize( mpeg2dec_t * mpeg2dec )
{
mpeg2dec->gop = mpeg2dec->new_gop;
mpeg2_reset_info( &(mpeg2dec->info) );
mpeg2dec->info.gop = &(mpeg2dec->gop);
info_user_data (mpeg2dec);
}
void mpeg2_set_fbuf( mpeg2dec_t * mpeg2dec, int b_type )
{
int i;
for( i = 0; i < 3; i++ )
{
if( (mpeg2dec->fbuf[1] != &mpeg2dec->fbuf_alloc[i].fbuf) &&
(mpeg2dec->fbuf[2] != &mpeg2dec->fbuf_alloc[i].fbuf) )
{
mpeg2dec->fbuf[0] = &mpeg2dec->fbuf_alloc[i].fbuf;
mpeg2dec->info.current_fbuf = mpeg2dec->fbuf[0];
if( b_type || (mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY) )
{
if( b_type || mpeg2dec->convert )
mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[0];
mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[0];
}
}
break;
}
}
mpeg2_state_t mpeg2_header_picture_start( mpeg2dec_t * mpeg2dec )
{
mpeg2_picture_t * picture = &(mpeg2dec->new_picture);
mpeg2dec->state = ((mpeg2dec->state != STATE_SLICE_1ST) ?
STATE_PICTURE : STATE_PICTURE_2ND);
picture->flags = 0;
picture->tag = picture->tag2 = 0;
if( mpeg2dec->num_tags )
{
if( mpeg2dec->bytes_since_tag >= 4 )
{
mpeg2dec->num_tags = 0;
picture->tag = mpeg2dec->tag_current;
picture->tag2 = mpeg2dec->tag2_current;
picture->flags = PIC_FLAG_TAGS;
}
else if( mpeg2dec->num_tags > 1 )
{
mpeg2dec->num_tags = 1;
picture->tag = mpeg2dec->tag_previous;
picture->tag2 = mpeg2dec->tag2_previous;
picture->flags = PIC_FLAG_TAGS;
}
}
picture->display_offset[0].x = picture->display_offset[1].x =
picture->display_offset[2].x = mpeg2dec->display_offset_x;
picture->display_offset[0].y = picture->display_offset[1].y =
picture->display_offset[2].y = mpeg2dec->display_offset_y;
return mpeg2_parse_header (mpeg2dec);
}
int mpeg2_header_picture( mpeg2dec_t * mpeg2dec )
{
uint8_t * buffer = mpeg2dec->chunk_start;
mpeg2_picture_t * picture = &(mpeg2dec->new_picture);
mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
int type;
type = (buffer [1] >> 3) & 7;
mpeg2dec->ext_state = PIC_CODING_EXT;
picture->temporal_reference = (buffer[0] << 2) | (buffer[1] >> 6);
picture->flags |= type;
if( (type == PIC_FLAG_CODING_TYPE_P) || (type == PIC_FLAG_CODING_TYPE_B) )
{
/* forward_f_code and backward_f_code - used in mpeg1 only */
decoder->f_motion.f_code[1] = (buffer[3] >> 2) & 1;
decoder->f_motion.f_code[0] =
(((buffer[3] << 1) | (buffer[4] >> 7)) & 7) - 1;
decoder->b_motion.f_code[1] = (buffer[4] >> 6) & 1;
decoder->b_motion.f_code[0] = ((buffer[4] >> 3) & 7) - 1;
}
/* XXXXXX decode extra_information_picture as well */
picture->nb_fields = 2;
mpeg2dec->q_scale_type = 0;
decoder->intra_dc_precision = 7;
decoder->frame_pred_frame_dct = 1;
decoder->concealment_motion_vectors = 0;
decoder->scan = mpeg2_scan_norm;
decoder->picture_structure = FRAME_PICTURE;
mpeg2dec->copy_matrix = 0;
return 0;
}
static int picture_coding_ext( mpeg2dec_t * mpeg2dec )
{
uint8_t * buffer = mpeg2dec->chunk_start;
mpeg2_picture_t * picture = &(mpeg2dec->new_picture);
mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
uint32_t flags;
/* pre subtract 1 for use later in compute_motion_vector */
decoder->f_motion.f_code[0] = (buffer[0] & 15) - 1;
decoder->f_motion.f_code[1] = (buffer[1] >> 4) - 1;
decoder->b_motion.f_code[0] = (buffer[1] & 15) - 1;
decoder->b_motion.f_code[1] = (buffer[2] >> 4) - 1;
flags = picture->flags;
decoder->intra_dc_precision = 7 - ((buffer[2] >> 2) & 3);
decoder->picture_structure = buffer[2] & 3;
switch (decoder->picture_structure)
{
case TOP_FIELD:
//flags |= PIC_FLAG_TOP_FIELD_FIRST;
case BOTTOM_FIELD:
picture->nb_fields = 1;
break;
case FRAME_PICTURE:
if( !(mpeg2dec->sequence.flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE) )
{
picture->nb_fields = (buffer[3] & 2) ? 3 : 2;
flags |= (buffer[3] & 128) ? PIC_FLAG_TOP_FIELD_FIRST : 0;
}
else
picture->nb_fields = (buffer[3]&2) ? ((buffer[3]&128) ? 6 : 4) : 2;
break;
default:
return 1;
}
decoder->top_field_first = buffer[3] >> 7;
if( decoder->top_field_first )
flags |= PIC_FLAG_TOP_FIELD_FIRST;
decoder->frame_pred_frame_dct = (buffer[3] >> 6) & 1;
decoder->concealment_motion_vectors = (buffer[3] >> 5) & 1;
decoder->q_scale_type = (buffer[3] >> 4) & 1;
mpeg2dec->q_scale_type = buffer[3] & 16;
decoder->intra_vlc_format = (buffer[3] >> 3) & 1;
decoder->scan = (buffer[3] & 4) ? mpeg2_scan_alt : mpeg2_scan_norm;
flags |= (buffer[4] & 0x80) ? PIC_FLAG_PROGRESSIVE_FRAME : 0;
if( buffer[4] & 0x40 )
flags |= (((buffer[4]<<26) | (buffer[5]<<18) | (buffer[6]<<10)) &
PIC_MASK_COMPOSITE_DISPLAY) | PIC_FLAG_COMPOSITE_DISPLAY;
picture->flags = flags;
mpeg2dec->ext_state = PIC_DISPLAY_EXT | COPYRIGHT_EXT | QUANT_MATRIX_EXT;
return 0;
}
static int picture_display_ext( mpeg2dec_t * mpeg2dec )
{
uint8_t * buffer = mpeg2dec->chunk_start;
mpeg2_picture_t * picture = &(mpeg2dec->new_picture);
int i, nb_pos;
nb_pos = picture->nb_fields;
if( mpeg2dec->sequence.flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE )
nb_pos >>= 1;
for( i = 0; i < nb_pos; i++ )
{
int x, y;
x = ((buffer[4*i] << 24) | (buffer[4*i+1] << 16) |
(buffer[4*i+2] << 8) | buffer[4*i+3]) >> (11-2*i);
y = ((buffer[4*i+2] << 24) | (buffer[4*i+3] << 16) |
(buffer[4*i+4] << 8) | buffer[4*i+5]) >> (10-2*i);
if( !(x & y & 1) )
return 1;
picture->display_offset[i].x = mpeg2dec->display_offset_x = x >> 1;
picture->display_offset[i].y = mpeg2dec->display_offset_y = y >> 1;
}
}
for( ; i < 3; i++ )
{
picture->display_offset[i].x = mpeg2dec->display_offset_x;
picture->display_offset[i].y = mpeg2dec->display_offset_y;
}
return 0;
}
void mpeg2_header_picture_finalize( mpeg2dec_t * mpeg2dec, uint32_t accels )
{
mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
int old_type_b = (decoder->coding_type == B_TYPE);
int low_delay = mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY;
finalize_matrix( mpeg2dec );
decoder->coding_type = mpeg2dec->new_picture.flags & PIC_MASK_CODING_TYPE;
/* move in header_process_picture_header */
decoder->second_field = (decoder->picture_structure != FRAME_PICTURE) &&
!(decoder->second_field);
if( mpeg2dec->state == STATE_PICTURE )
{
mpeg2_picture_t * picture;
mpeg2_picture_t * other;
/* decoder->second_field = 0; */
picture = other = mpeg2dec->pictures;
if( old_type_b ^ (mpeg2dec->picture < mpeg2dec->pictures + 2) )
picture += 2;
else
other += 2;
mpeg2dec->picture = picture;
*picture = mpeg2dec->new_picture;
if( !old_type_b )
{
mpeg2dec->fbuf[2] = mpeg2dec->fbuf[1];
mpeg2dec->fbuf[1] = mpeg2dec->fbuf[0];
}
mpeg2dec->fbuf[0] = NULL;
mpeg2_reset_info (&(mpeg2dec->info));
mpeg2dec->info.current_picture = picture;
mpeg2dec->info.display_picture = picture;
if( decoder->coding_type != B_TYPE )
{
if (!low_delay)
{
if (mpeg2dec->first)
{
mpeg2dec->info.display_picture = NULL;
mpeg2dec->first = 0;
}
else
{
mpeg2dec->info.display_picture = other;
if (other->nb_fields == 1)
mpeg2dec->info.display_picture_2nd = other + 1;
mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[1];
}
}
if( !low_delay + !mpeg2dec->convert )
mpeg2dec->info.discard_fbuf =
mpeg2dec->fbuf[!low_delay + !mpeg2dec->convert];
}
if (mpeg2dec->convert)
{
mpeg2_convert_init_t convert_init;
if (!mpeg2dec->convert_start)
{
int y_size, uv_size;
mpeg2dec->decoder.convert_id =
mpeg2_malloc( mpeg2dec->convert_id_size,
MPEG2_ALLOC_CONVERT_ID );
mpeg2dec->convert( MPEG2_CONVERT_START,
mpeg2dec->decoder.convert_id,
&(mpeg2dec->sequence),
mpeg2dec->convert_stride, accels,
mpeg2dec->convert_arg, &convert_init );
mpeg2dec->convert_start = convert_init.start;
mpeg2dec->decoder.convert = convert_init.copy;
y_size = decoder->stride_frame * mpeg2dec->sequence.height;
uv_size = y_size >> (2 - mpeg2dec->decoder.chroma_format);
mpeg2dec->yuv_buf[0][0] =
(uint8_t *) mpeg2_malloc (y_size, MPEG2_ALLOC_YUV);
mpeg2dec->yuv_buf[0][1] =
(uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
mpeg2dec->yuv_buf[0][2] =
(uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
mpeg2dec->yuv_buf[1][0] =
(uint8_t *) mpeg2_malloc (y_size, MPEG2_ALLOC_YUV);
mpeg2dec->yuv_buf[1][1] =
(uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
mpeg2dec->yuv_buf[1][2] =
(uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
y_size = decoder->stride_frame * 32;
uv_size = y_size >> (2 - mpeg2dec->decoder.chroma_format);
mpeg2dec->yuv_buf[2][0] =
(uint8_t *) mpeg2_malloc (y_size, MPEG2_ALLOC_YUV);
mpeg2dec->yuv_buf[2][1] =
(uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
mpeg2dec->yuv_buf[2][2] =
(uint8_t *) mpeg2_malloc (uv_size, MPEG2_ALLOC_YUV);
}
if (!mpeg2dec->custom_fbuf)
{
while( mpeg2dec->alloc_index < 3 )
{
mpeg2_fbuf_t * fbuf;
fbuf = &mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index++].fbuf;
fbuf->id = NULL;
fbuf->buf[0] =
(uint8_t *) mpeg2_malloc( convert_init.buf_size[0],
MPEG2_ALLOC_CONVERTED );
fbuf->buf[1] =
(uint8_t *) mpeg2_malloc( convert_init.buf_size[1],
MPEG2_ALLOC_CONVERTED );
fbuf->buf[2] =
(uint8_t *) mpeg2_malloc( convert_init.buf_size[2],
MPEG2_ALLOC_CONVERTED );
}
mpeg2_set_fbuf( mpeg2dec, (decoder->coding_type == B_TYPE) );
}
}
else if( !mpeg2dec->custom_fbuf )
{
while (mpeg2dec->alloc_index < 3)
{
mpeg2_fbuf_t * fbuf;
int y_size, uv_size;
fbuf = &(mpeg2dec->fbuf_alloc[mpeg2dec->alloc_index++].fbuf);
fbuf->id = NULL;
y_size = decoder->stride_frame * mpeg2dec->sequence.height;
uv_size = y_size >> (2 - decoder->chroma_format);
fbuf->buf[0] = (uint8_t *) mpeg2_malloc( y_size,
MPEG2_ALLOC_YUV );
fbuf->buf[1] = (uint8_t *) mpeg2_malloc( uv_size,
MPEG2_ALLOC_YUV );
fbuf->buf[2] = (uint8_t *) mpeg2_malloc( uv_size,
MPEG2_ALLOC_YUV );
}
mpeg2_set_fbuf (mpeg2dec, (decoder->coding_type == B_TYPE));
}
}
else
{
/* decoder->second_field = 1; */
mpeg2dec->picture++; /* second field picture */
*(mpeg2dec->picture) = mpeg2dec->new_picture;
mpeg2dec->info.current_picture_2nd = mpeg2dec->picture;
if (low_delay || decoder->coding_type == B_TYPE)
mpeg2dec->info.display_picture_2nd = mpeg2dec->picture;
}
info_user_data( mpeg2dec );
}
static int copyright_ext( mpeg2dec_t * mpeg2dec )
{
return 0;
}
static int quant_matrix_ext( mpeg2dec_t * mpeg2dec )
{
uint8_t * buffer = mpeg2dec->chunk_start;
int i, j;
for (i = 0; i < 4; i++)
{
if (buffer[0] & (8 >> i))
{
for (j = 0; j < 64; j++)
mpeg2dec->new_quantizer_matrix[i][mpeg2_scan_norm[j]] =
(buffer[j] << (i+5)) | (buffer[j+1] >> (3-i));
mpeg2dec->copy_matrix |= 1 << i;
buffer += 64;
}
}
return 0;
}
int mpeg2_header_extension( mpeg2dec_t * mpeg2dec )
{
static int (* parser[]) (mpeg2dec_t *) = {
0, sequence_ext, sequence_display_ext, quant_matrix_ext,
copyright_ext, 0, 0, picture_display_ext, picture_coding_ext
};
int ext, ext_bit;
ext = mpeg2dec->chunk_start[0] >> 4;
ext_bit = 1 << ext;
if( !(mpeg2dec->ext_state & ext_bit) )
return 0; /* ignore illegal extensions */
mpeg2dec->ext_state &= ~ext_bit;
return parser[ext] (mpeg2dec);
}
int mpeg2_header_user_data( mpeg2dec_t * mpeg2dec )
{
mpeg2dec->user_data_len += mpeg2dec->chunk_ptr - 1 - mpeg2dec->chunk_start;
mpeg2dec->chunk_start = mpeg2dec->chunk_ptr - 1;
return 0;
}
static void prescale( mpeg2dec_t * mpeg2dec, int index )
{
static int non_linear_scale [] =
{
0, 1, 2, 3, 4, 5, 6, 7,
8, 10, 12, 14, 16, 18, 20, 22,
24, 28, 32, 36, 40, 44, 48, 52,
56, 64, 72, 80, 88, 96, 104, 112
};
int i, j, k;
mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
if( mpeg2dec->scaled[index] != mpeg2dec->q_scale_type )
{
mpeg2dec->scaled[index] = mpeg2dec->q_scale_type;
for( i = 0; i < 32; i++ )
{
k = mpeg2dec->q_scale_type ? non_linear_scale[i] : (i << 1);
for( j = 0; j < 64; j++ )
decoder->quantizer_prescale[index][i][j] =
k * mpeg2dec->quantizer_matrix[index][j];
}
}
}
mpeg2_state_t mpeg2_header_slice_start( mpeg2dec_t * mpeg2dec )
{
mpeg2_decoder_t * decoder = &(mpeg2dec->decoder);
mpeg2dec->info.user_data = NULL;
mpeg2dec->info.user_data_len = 0;
mpeg2dec->state = ((mpeg2dec->picture->nb_fields > 1 ||
mpeg2dec->state == STATE_PICTURE_2ND) ?
STATE_SLICE : STATE_SLICE_1ST);
if (mpeg2dec->decoder.coding_type != D_TYPE)
{
prescale (mpeg2dec, 0);
if( decoder->chroma_quantizer[0] == decoder->quantizer_prescale[2] )
prescale (mpeg2dec, 2);
if( mpeg2dec->decoder.coding_type != I_TYPE )
{
prescale (mpeg2dec, 1);
if( decoder->chroma_quantizer[1] == decoder->quantizer_prescale[3] )
prescale (mpeg2dec, 3);
}
}
if( !(mpeg2dec->nb_decode_slices) )
mpeg2dec->picture->flags |= PIC_FLAG_SKIP;
else if( mpeg2dec->convert_start )
{
mpeg2dec->convert_start( decoder->convert_id, mpeg2dec->fbuf[0],
mpeg2dec->picture, mpeg2dec->info.gop );
if( mpeg2dec->decoder.coding_type == B_TYPE )
mpeg2_init_fbuf( &(mpeg2dec->decoder), mpeg2dec->yuv_buf[2],
mpeg2dec->yuv_buf[mpeg2dec->yuv_index ^ 1],
mpeg2dec->yuv_buf[mpeg2dec->yuv_index] );
else
{
mpeg2_init_fbuf( &(mpeg2dec->decoder),
mpeg2dec->yuv_buf[mpeg2dec->yuv_index ^ 1],
mpeg2dec->yuv_buf[mpeg2dec->yuv_index],
mpeg2dec->yuv_buf[mpeg2dec->yuv_index] );
if( mpeg2dec->state == STATE_SLICE )
mpeg2dec->yuv_index ^= 1;
}
}
else
{
int b_type;
b_type = (mpeg2dec->decoder.coding_type == B_TYPE);
mpeg2_init_fbuf( &(mpeg2dec->decoder), mpeg2dec->fbuf[0]->buf,
mpeg2dec->fbuf[b_type + 1]->buf,
mpeg2dec->fbuf[b_type]->buf );
}
mpeg2dec->action = NULL;
return (mpeg2_state_t)-1;
}
static mpeg2_state_t seek_sequence (mpeg2dec_t * mpeg2dec)
{
mpeg2_reset_info (&(mpeg2dec->info));
mpeg2dec->info.sequence = NULL;
mpeg2dec->info.gop = NULL;
mpeg2_header_state_init (mpeg2dec);
mpeg2dec->action = mpeg2_seek_header;
return mpeg2_seek_header (mpeg2dec);
}
mpeg2_state_t mpeg2_header_end (mpeg2dec_t * mpeg2dec)
{
mpeg2_picture_t * picture;
int b_type;
b_type = (mpeg2dec->decoder.coding_type == B_TYPE);
picture = mpeg2dec->pictures;
if( (mpeg2dec->picture >= picture + 2) ^ b_type )
picture = mpeg2dec->pictures + 2;
mpeg2_reset_info (&(mpeg2dec->info));
if( !(mpeg2dec->sequence.flags & SEQ_FLAG_LOW_DELAY) )
{
mpeg2dec->info.display_picture = picture;
if( picture->nb_fields == 1 )
mpeg2dec->info.display_picture_2nd = picture + 1;
mpeg2dec->info.display_fbuf = mpeg2dec->fbuf[b_type];
if( !mpeg2dec->convert )
mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[b_type + 1];
}
else if( !mpeg2dec->convert )
mpeg2dec->info.discard_fbuf = mpeg2dec->fbuf[b_type];
mpeg2dec->action = seek_sequence;
return STATE_END;
}
/* $Id:$
* motion_comp.c
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#include "config.h"
#include <inttypes.h>
#include "mpeg2.h"
#include "attributes.h"
#include "mpeg2_internal.h"
mpeg2_mc_t mpeg2_mc;
void mpeg2_mc_init (uint32_t accel)
{
if (accel & MPEG2_ACCEL_X86_MMXEXT)
mpeg2_mc = mpeg2_mc_mmxext;
else if (accel & MPEG2_ACCEL_X86_3DNOW)
mpeg2_mc = mpeg2_mc_3dnow;
else if (accel & MPEG2_ACCEL_X86_MMX)
mpeg2_mc = mpeg2_mc_mmx;
else
mpeg2_mc = mpeg2_mc_c;
}
#define avg2(a,b) ((a+b+1)>>1)
#define avg4(a,b,c,d) ((a+b+c+d+2)>>2)
#define predict_o(i) (ref[i])
#define predict_x(i) (avg2 (ref[i], ref[i+1]))
#define predict_y(i) (avg2 (ref[i], (ref+stride)[i]))
#define predict_xy(i) (avg4 (ref[i], ref[i+1], \
(ref+stride)[i], (ref+stride)[i+1]))
#define put(predictor,i) dest[i] = predictor (i)
#define avg(predictor,i) dest[i] = avg2 (predictor (i), dest[i])
/* mc function template */
#define MC_FUNC(op,xy) \
static void MC_##op##_##xy##_16_c (uint8_t * dest, const uint8_t * ref, \
const int stride, int height) \
{ \
do { \
op (predict_##xy, 0); \
op (predict_##xy, 1); \
op (predict_##xy, 2); \
op (predict_##xy, 3); \
op (predict_##xy, 4); \
op (predict_##xy, 5); \
op (predict_##xy, 6); \
op (predict_##xy, 7); \
op (predict_##xy, 8); \
op (predict_##xy, 9); \
op (predict_##xy, 10); \
op (predict_##xy, 11); \
op (predict_##xy, 12); \
op (predict_##xy, 13); \
op (predict_##xy, 14); \
op (predict_##xy, 15); \
ref += stride; \
dest += stride; \
} while (--height); \
} \
static void MC_##op##_##xy##_8_c (uint8_t * dest, const uint8_t * ref, \
const int stride, int height) \
{ \
do { \
op (predict_##xy, 0); \
op (predict_##xy, 1); \
op (predict_##xy, 2); \
op (predict_##xy, 3); \
op (predict_##xy, 4); \
op (predict_##xy, 5); \
op (predict_##xy, 6); \
op (predict_##xy, 7); \
ref += stride; \
dest += stride; \
} while (--height); \
}
/* definitions of the actual mc functions */
MC_FUNC (put,o)
MC_FUNC (avg,o)
MC_FUNC (put,x)
MC_FUNC (avg,x)
MC_FUNC (put,y)
MC_FUNC (avg,y)
MC_FUNC (put,xy)
MC_FUNC (avg,xy)
MPEG2_MC_EXTERN (c)
/* $Id:$
* motion_comp_mmx.c
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#include "config.h"
#include <inttypes.h>
#include "mpeg2.h"
#include "attributes.h"
#include "mpeg2_internal.h"
#include "mmx.h"
#define CPU_MMXEXT 0
#define CPU_3DNOW 1
/* MMX code - needs a rewrite */
/*
* Motion Compensation frequently needs to average values using the
* formula (x+y+1)>>1. Both MMXEXT and 3Dnow include one instruction
* to compute this, but it's been left out of classic MMX.
*
* We need to be careful of overflows when doing this computation.
* Rather than unpacking data to 16-bits, which reduces parallelism,
* we use the following formulas:
*
* (x+y)>>1 == (x&y)+((x^y)>>1)
* (x+y+1)>>1 == (x|y)-((x^y)>>1)
*/
/* some rounding constants */
static mmx_t mask1 = {0xfefefefefefefefeLL};
static mmx_t round4 = {0x0002000200020002LL};
/*
* This code should probably be compiled with loop unrolling
* (ie, -funroll-loops in gcc)becuase some of the loops
* use a small static number of iterations. This was written
* with the assumption the compiler knows best about when
* unrolling will help
*/
static inline void mmx_zero_reg ()
{
/* load 0 into mm0 */
pxor_r2r (mm0, mm0);
}
static inline void mmx_average_2_U8 (uint8_t * dest, const uint8_t * src1,
const uint8_t * src2)
{
/* *dest = (*src1 + *src2 + 1)/ 2; */
movq_m2r (*src1, mm1); /* load 8 src1 bytes */
movq_r2r (mm1, mm2); /* copy 8 src1 bytes */
movq_m2r (*src2, mm3); /* load 8 src2 bytes */
movq_r2r (mm3, mm4); /* copy 8 src2 bytes */
pxor_r2r (mm1, mm3); /* xor src1 and src2 */
pand_m2r (mask1, mm3); /* mask lower bits */
psrlq_i2r (1, mm3); /* /2 */
por_r2r (mm2, mm4); /* or src1 and src2 */
psubb_r2r (mm3, mm4); /* subtract subresults */
movq_r2m (mm4, *dest); /* store result in dest */
}
static inline void mmx_interp_average_2_U8 (uint8_t * dest,
const uint8_t * src1,
const uint8_t * src2)
{
/* *dest = (*dest + (*src1 + *src2 + 1)/ 2 + 1)/ 2; */
movq_m2r (*dest, mm1); /* load 8 dest bytes */
movq_r2r (mm1, mm2); /* copy 8 dest bytes */
movq_m2r (*src1, mm3); /* load 8 src1 bytes */
movq_r2r (mm3, mm4); /* copy 8 src1 bytes */
movq_m2r (*src2, mm5); /* load 8 src2 bytes */
movq_r2r (mm5, mm6); /* copy 8 src2 bytes */
pxor_r2r (mm3, mm5); /* xor src1 and src2 */
pand_m2r (mask1, mm5); /* mask lower bits */
psrlq_i2r (1, mm5); /* /2 */
por_r2r (mm4, mm6); /* or src1 and src2 */
psubb_r2r (mm5, mm6); /* subtract subresults */
movq_r2r (mm6, mm5); /* copy subresult */
pxor_r2r (mm1, mm5); /* xor srcavg and dest */
pand_m2r (mask1, mm5); /* mask lower bits */
psrlq_i2r (1, mm5); /* /2 */
por_r2r (mm2, mm6); /* or srcavg and dest */
psubb_r2r (mm5, mm6); /* subtract subresults */
movq_r2m (mm6, *dest); /* store result in dest */
}
static inline void mmx_average_4_U8 (uint8_t * dest, const uint8_t * src1,
const uint8_t * src2,
const uint8_t * src3,
const uint8_t * src4)
{
/* *dest = (*src1 + *src2 + *src3 + *src4 + 2)/ 4; */
movq_m2r (*src1, mm1); /* load 8 src1 bytes */
movq_r2r (mm1, mm2); /* copy 8 src1 bytes */
punpcklbw_r2r (mm0, mm1); /* unpack low src1 bytes */
punpckhbw_r2r (mm0, mm2); /* unpack high src1 bytes */
movq_m2r (*src2, mm3); /* load 8 src2 bytes */
movq_r2r (mm3, mm4); /* copy 8 src2 bytes */
punpcklbw_r2r (mm0, mm3); /* unpack low src2 bytes */
punpckhbw_r2r (mm0, mm4); /* unpack high src2 bytes */
paddw_r2r (mm3, mm1); /* add lows */
paddw_r2r (mm4, mm2); /* add highs */
/* now have partials in mm1 and mm2 */
movq_m2r (*src3, mm3); /* load 8 src3 bytes */
movq_r2r (mm3, mm4); /* copy 8 src3 bytes */
punpcklbw_r2r (mm0, mm3); /* unpack low src3 bytes */
punpckhbw_r2r (mm0, mm4); /* unpack high src3 bytes */
paddw_r2r (mm3, mm1); /* add lows */
paddw_r2r (mm4, mm2); /* add highs */
movq_m2r (*src4, mm5); /* load 8 src4 bytes */
movq_r2r (mm5, mm6); /* copy 8 src4 bytes */
punpcklbw_r2r (mm0, mm5); /* unpack low src4 bytes */
punpckhbw_r2r (mm0, mm6); /* unpack high src4 bytes */
paddw_r2r (mm5, mm1); /* add lows */
paddw_r2r (mm6, mm2); /* add highs */
/* now have subtotal in mm1 and mm2 */
paddw_m2r (round4, mm1);
psraw_i2r (2, mm1); /* /4 */
paddw_m2r (round4, mm2);
psraw_i2r (2, mm2); /* /4 */
packuswb_r2r (mm2, mm1); /* pack (w/ saturation) */
movq_r2m (mm1, *dest); /* store result in dest */
}
static inline void mmx_interp_average_4_U8 (uint8_t * dest,
const uint8_t * src1,
const uint8_t * src2,
const uint8_t * src3,
const uint8_t * src4)
{
/* *dest = (*dest + (*src1 + *src2 + *src3 + *src4 + 2)/ 4 + 1)/ 2; */
movq_m2r (*src1, mm1); /* load 8 src1 bytes */
movq_r2r (mm1, mm2); /* copy 8 src1 bytes */
punpcklbw_r2r (mm0, mm1); /* unpack low src1 bytes */
punpckhbw_r2r (mm0, mm2); /* unpack high src1 bytes */
movq_m2r (*src2, mm3); /* load 8 src2 bytes */
movq_r2r (mm3, mm4); /* copy 8 src2 bytes */
punpcklbw_r2r (mm0, mm3); /* unpack low src2 bytes */
punpckhbw_r2r (mm0, mm4); /* unpack high src2 bytes */
paddw_r2r (mm3, mm1); /* add lows */
paddw_r2r (mm4, mm2); /* add highs */
/* now have partials in mm1 and mm2 */
movq_m2r (*src3, mm3); /* load 8 src3 bytes */
movq_r2r (mm3, mm4); /* copy 8 src3 bytes */
punpcklbw_r2r (mm0, mm3); /* unpack low src3 bytes */
punpckhbw_r2r (mm0, mm4); /* unpack high src3 bytes */
paddw_r2r (mm3, mm1); /* add lows */
paddw_r2r (mm4, mm2); /* add highs */
movq_m2r (*src4, mm5); /* load 8 src4 bytes */
movq_r2r (mm5, mm6); /* copy 8 src4 bytes */
punpcklbw_r2r (mm0, mm5); /* unpack low src4 bytes */
punpckhbw_r2r (mm0, mm6); /* unpack high src4 bytes */
paddw_r2r (mm5, mm1); /* add lows */
paddw_r2r (mm6, mm2); /* add highs */
paddw_m2r (round4, mm1);
psraw_i2r (2, mm1); /* /4 */
paddw_m2r (round4, mm2);
psraw_i2r (2, mm2); /* /4 */
/* now have subtotal/4 in mm1 and mm2 */
movq_m2r (*dest, mm3); /* load 8 dest bytes */
movq_r2r (mm3, mm4); /* copy 8 dest bytes */
packuswb_r2r (mm2, mm1); /* pack (w/ saturation) */
movq_r2r (mm1,mm2); /* copy subresult */
pxor_r2r (mm1, mm3); /* xor srcavg and dest */
pand_m2r (mask1, mm3); /* mask lower bits */
psrlq_i2r (1, mm3); /* /2 */
por_r2r (mm2, mm4); /* or srcavg and dest */
psubb_r2r (mm3, mm4); /* subtract subresults */
movq_r2m (mm4, *dest); /* store result in dest */
}
/*-----------------------------------------------------------------------*/
static inline void MC_avg_mmx (const int width, int height, uint8_t * dest,
const uint8_t * ref, const int stride)
{
mmx_zero_reg ();
do
{
mmx_average_2_U8 (dest, dest, ref);
if (width == 16)
mmx_average_2_U8 (dest+8, dest+8, ref+8);
dest += stride;
ref += stride;
} while( --height );
}
static void MC_avg_o_16_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg_mmx (16, height, dest, ref, stride);
}
static void MC_avg_o_8_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg_mmx (8, height, dest, ref, stride);
}
/*-----------------------------------------------------------------------*/
static inline void MC_put_mmx (const int width, int height, uint8_t * dest,
const uint8_t * ref, const int stride)
{
mmx_zero_reg ();
do
{
movq_m2r (* ref, mm1); /* load 8 ref bytes */
movq_r2m (mm1,* dest); /* store 8 bytes at curr */
if( width == 16 )
{
movq_m2r (* (ref+8), mm1); /* load 8 ref bytes */
movq_r2m (mm1,* (dest+8)); /* store 8 bytes at curr */
}
dest += stride;
ref += stride;
} while( --height );
}
static void MC_put_o_16_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put_mmx (16, height, dest, ref, stride);
}
static void MC_put_o_8_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put_mmx (8, height, dest, ref, stride);
}
/*-----------------------------------------------------------------------*/
/* Half pixel interpolation in the x direction */
static inline void MC_avg_x_mmx (const int width, int height, uint8_t * dest,
const uint8_t * ref, const int stride)
{
mmx_zero_reg ();
do
{
mmx_interp_average_2_U8 (dest, ref, ref+1);
if (width == 16)
mmx_interp_average_2_U8 (dest+8, ref+8, ref+9);
dest += stride;
ref += stride;
} while( --height );
}
static void MC_avg_x_16_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg_x_mmx (16, height, dest, ref, stride);
}
static void MC_avg_x_8_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg_x_mmx (8, height, dest, ref, stride);
}
/*-----------------------------------------------------------------------*/
static inline void MC_put_x_mmx (const int width, int height, uint8_t * dest,
const uint8_t * ref, const int stride)
{
mmx_zero_reg ();
do
{
mmx_average_2_U8 (dest, ref, ref+1);
if (width == 16)
mmx_average_2_U8 (dest+8, ref+8, ref+9);
dest += stride;
ref += stride;
} while (--height);
}
static void MC_put_x_16_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put_x_mmx (16, height, dest, ref, stride);
}
static void MC_put_x_8_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put_x_mmx (8, height, dest, ref, stride);
}
/*-----------------------------------------------------------------------*/
static inline void MC_avg_xy_mmx (const int width, int height, uint8_t * dest,
const uint8_t * ref, const int stride)
{
const uint8_t * ref_next = ref + stride;
mmx_zero_reg ();
do
{
mmx_interp_average_4_U8 (dest, ref, ref+1, ref_next, ref_next+1);
if (width == 16)
mmx_interp_average_4_U8( dest+8, ref+8, ref+9,
ref_next+8, ref_next+9 );
dest += stride;
ref += stride;
ref_next += stride;
} while( --height );
}
static void MC_avg_xy_16_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg_xy_mmx (16, height, dest, ref, stride);
}
static void MC_avg_xy_8_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg_xy_mmx (8, height, dest, ref, stride);
}
/*-----------------------------------------------------------------------*/
static inline void MC_put_xy_mmx (const int width, int height, uint8_t * dest,
const uint8_t * ref, const int stride)
{
const uint8_t * ref_next = ref + stride;
mmx_zero_reg ();
do
{
mmx_average_4_U8 (dest, ref, ref+1, ref_next, ref_next+1);
if (width == 16)
mmx_average_4_U8( dest+8, ref+8, ref+9, ref_next+8, ref_next+9 );
dest += stride;
ref += stride;
ref_next += stride;
} while (--height);
}
static void MC_put_xy_16_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put_xy_mmx (16, height, dest, ref, stride);
}
static void MC_put_xy_8_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put_xy_mmx (8, height, dest, ref, stride);
}
/*-----------------------------------------------------------------------*/
static inline void MC_avg_y_mmx (const int width, int height, uint8_t * dest,
const uint8_t * ref, const int stride)
{
const uint8_t * ref_next = ref + stride;
mmx_zero_reg ();
do
{
mmx_interp_average_2_U8 (dest, ref, ref_next);
if (width == 16)
mmx_interp_average_2_U8( dest+8, ref+8, ref_next+8 );
dest += stride;
ref += stride;
ref_next += stride;
} while (--height);
}
static void MC_avg_y_16_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg_y_mmx (16, height, dest, ref, stride);
}
static void MC_avg_y_8_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg_y_mmx (8, height, dest, ref, stride);
}
/*-----------------------------------------------------------------------*/
static inline void MC_put_y_mmx (const int width, int height, uint8_t * dest,
const uint8_t * ref, const int stride)
{
const uint8_t * ref_next = ref + stride;
mmx_zero_reg ();
do
{
mmx_average_2_U8 (dest, ref, ref_next);
if (width == 16)
mmx_average_2_U8( dest+8, ref+8, ref_next+8 );
dest += stride;
ref += stride;
ref_next += stride;
} while (--height);
}
static void MC_put_y_16_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put_y_mmx (16, height, dest, ref, stride);
}
static void MC_put_y_8_mmx (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put_y_mmx (8, height, dest, ref, stride);
}
MPEG2_MC_EXTERN (mmx)
/* CPU_MMXEXT/CPU_3DNOW adaptation layer */
#define pavg_r2r(src,dest) \
do { \
if (cpu == CPU_MMXEXT) \
pavgb_r2r (src, dest); \
else \
pavgusb_r2r (src, dest); \
} while (0)
#define pavg_m2r(src,dest) \
do { \
if (cpu == CPU_MMXEXT) \
pavgb_m2r (src, dest); \
else \
pavgusb_m2r (src, dest); \
} while (0)
/* CPU_MMXEXT code */
static inline void MC_put1_8 (int height, uint8_t * dest, const uint8_t * ref,
const int stride)
{
do {
movq_m2r (*ref, mm0);
movq_r2m (mm0, *dest);
ref += stride;
dest += stride;
} while (--height);
}
static inline void MC_put1_16 (int height, uint8_t * dest, const uint8_t * ref,
const int stride)
{
do {
movq_m2r (*ref, mm0);
movq_m2r (*(ref+8), mm1);
ref += stride;
movq_r2m (mm0, *dest);
movq_r2m (mm1, *(dest+8));
dest += stride;
} while (--height);
}
static inline void MC_avg1_8 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int cpu)
{
do {
movq_m2r (*ref, mm0);
pavg_m2r (*dest, mm0);
ref += stride;
movq_r2m (mm0, *dest);
dest += stride;
} while (--height);
}
static inline void MC_avg1_16 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int cpu)
{
do {
movq_m2r (*ref, mm0);
movq_m2r (*(ref+8), mm1);
pavg_m2r (*dest, mm0);
pavg_m2r (*(dest+8), mm1);
movq_r2m (mm0, *dest);
ref += stride;
movq_r2m (mm1, *(dest+8));
dest += stride;
} while (--height);
}
static inline void MC_put2_8 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int offset,
const int cpu)
{
do {
movq_m2r (*ref, mm0);
pavg_m2r (*(ref+offset), mm0);
ref += stride;
movq_r2m (mm0, *dest);
dest += stride;
} while (--height);
}
static inline void MC_put2_16 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int offset,
const int cpu)
{
do {
movq_m2r (*ref, mm0);
movq_m2r (*(ref+8), mm1);
pavg_m2r (*(ref+offset), mm0);
pavg_m2r (*(ref+offset+8), mm1);
movq_r2m (mm0, *dest);
ref += stride;
movq_r2m (mm1, *(dest+8));
dest += stride;
} while (--height);
}
static inline void MC_avg2_8 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int offset,
const int cpu)
{
do {
movq_m2r (*ref, mm0);
pavg_m2r (*(ref+offset), mm0);
pavg_m2r (*dest, mm0);
ref += stride;
movq_r2m (mm0, *dest);
dest += stride;
} while (--height);
}
static inline void MC_avg2_16 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int offset,
const int cpu)
{
do {
movq_m2r (*ref, mm0);
movq_m2r (*(ref+8), mm1);
pavg_m2r (*(ref+offset), mm0);
pavg_m2r (*(ref+offset+8), mm1);
pavg_m2r (*dest, mm0);
pavg_m2r (*(dest+8), mm1);
ref += stride;
movq_r2m (mm0, *dest);
movq_r2m (mm1, *(dest+8));
dest += stride;
} while (--height);
}
static mmx_t mask_one = {0x0101010101010101LL};
static inline void MC_put4_8 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int cpu)
{
movq_m2r (*ref, mm0);
movq_m2r (*(ref+1), mm1);
movq_r2r (mm0, mm7);
pxor_r2r (mm1, mm7);
pavg_r2r (mm1, mm0);
ref += stride;
do {
movq_m2r (*ref, mm2);
movq_r2r (mm0, mm5);
movq_m2r (*(ref+1), mm3);
movq_r2r (mm2, mm6);
pxor_r2r (mm3, mm6);
pavg_r2r (mm3, mm2);
por_r2r (mm6, mm7);
pxor_r2r (mm2, mm5);
pand_r2r (mm5, mm7);
pavg_r2r (mm2, mm0);
pand_m2r (mask_one, mm7);
psubusb_r2r (mm7, mm0);
ref += stride;
movq_r2m (mm0, *dest);
dest += stride;
movq_r2r (mm6, mm7); /* unroll ! */
movq_r2r (mm2, mm0); /* unroll ! */
} while (--height);
}
static inline void MC_put4_16 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int cpu)
{
do {
movq_m2r (*ref, mm0);
movq_m2r (*(ref+stride+1), mm1);
movq_r2r (mm0, mm7);
movq_m2r (*(ref+1), mm2);
pxor_r2r (mm1, mm7);
movq_m2r (*(ref+stride), mm3);
movq_r2r (mm2, mm6);
pxor_r2r (mm3, mm6);
pavg_r2r (mm1, mm0);
pavg_r2r (mm3, mm2);
por_r2r (mm6, mm7);
movq_r2r (mm0, mm6);
pxor_r2r (mm2, mm6);
pand_r2r (mm6, mm7);
pand_m2r (mask_one, mm7);
pavg_r2r (mm2, mm0);
psubusb_r2r (mm7, mm0);
movq_r2m (mm0, *dest);
movq_m2r (*(ref+8), mm0);
movq_m2r (*(ref+stride+9), mm1);
movq_r2r (mm0, mm7);
movq_m2r (*(ref+9), mm2);
pxor_r2r (mm1, mm7);
movq_m2r (*(ref+stride+8), mm3);
movq_r2r (mm2, mm6);
pxor_r2r (mm3, mm6);
pavg_r2r (mm1, mm0);
pavg_r2r (mm3, mm2);
por_r2r (mm6, mm7);
movq_r2r (mm0, mm6);
pxor_r2r (mm2, mm6);
pand_r2r (mm6, mm7);
pand_m2r (mask_one, mm7);
pavg_r2r (mm2, mm0);
psubusb_r2r (mm7, mm0);
ref += stride;
movq_r2m (mm0, *(dest+8));
dest += stride;
} while (--height);
}
static inline void MC_avg4_8 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int cpu)
{
do {
movq_m2r (*ref, mm0);
movq_m2r (*(ref+stride+1), mm1);
movq_r2r (mm0, mm7);
movq_m2r (*(ref+1), mm2);
pxor_r2r (mm1, mm7);
movq_m2r (*(ref+stride), mm3);
movq_r2r (mm2, mm6);
pxor_r2r (mm3, mm6);
pavg_r2r (mm1, mm0);
pavg_r2r (mm3, mm2);
por_r2r (mm6, mm7);
movq_r2r (mm0, mm6);
pxor_r2r (mm2, mm6);
pand_r2r (mm6, mm7);
pand_m2r (mask_one, mm7);
pavg_r2r (mm2, mm0);
psubusb_r2r (mm7, mm0);
movq_m2r (*dest, mm1);
pavg_r2r (mm1, mm0);
ref += stride;
movq_r2m (mm0, *dest);
dest += stride;
} while (--height);
}
static inline void MC_avg4_16 (int height, uint8_t * dest, const uint8_t * ref,
const int stride, const int cpu)
{
do {
movq_m2r (*ref, mm0);
movq_m2r (*(ref+stride+1), mm1);
movq_r2r (mm0, mm7);
movq_m2r (*(ref+1), mm2);
pxor_r2r (mm1, mm7);
movq_m2r (*(ref+stride), mm3);
movq_r2r (mm2, mm6);
pxor_r2r (mm3, mm6);
pavg_r2r (mm1, mm0);
pavg_r2r (mm3, mm2);
por_r2r (mm6, mm7);
movq_r2r (mm0, mm6);
pxor_r2r (mm2, mm6);
pand_r2r (mm6, mm7);
pand_m2r (mask_one, mm7);
pavg_r2r (mm2, mm0);
psubusb_r2r (mm7, mm0);
movq_m2r (*dest, mm1);
pavg_r2r (mm1, mm0);
movq_r2m (mm0, *dest);
movq_m2r (*(ref+8), mm0);
movq_m2r (*(ref+stride+9), mm1);
movq_r2r (mm0, mm7);
movq_m2r (*(ref+9), mm2);
pxor_r2r (mm1, mm7);
movq_m2r (*(ref+stride+8), mm3);
movq_r2r (mm2, mm6);
pxor_r2r (mm3, mm6);
pavg_r2r (mm1, mm0);
pavg_r2r (mm3, mm2);
por_r2r (mm6, mm7);
movq_r2r (mm0, mm6);
pxor_r2r (mm2, mm6);
pand_r2r (mm6, mm7);
pand_m2r (mask_one, mm7);
pavg_r2r (mm2, mm0);
psubusb_r2r (mm7, mm0);
movq_m2r (*(dest+8), mm1);
pavg_r2r (mm1, mm0);
ref += stride;
movq_r2m (mm0, *(dest+8));
dest += stride;
} while (--height);
}
static void MC_avg_o_16_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg1_16 (height, dest, ref, stride, CPU_MMXEXT);
}
static void MC_avg_o_8_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg1_8 (height, dest, ref, stride, CPU_MMXEXT);
}
static void MC_put_o_16_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put1_16 (height, dest, ref, stride);
}
static void MC_put_o_8_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put1_8 (height, dest, ref, stride);
}
static void MC_avg_x_16_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg2_16 (height, dest, ref, stride, 1, CPU_MMXEXT);
}
static void MC_avg_x_8_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg2_8 (height, dest, ref, stride, 1, CPU_MMXEXT);
}
static void MC_put_x_16_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put2_16 (height, dest, ref, stride, 1, CPU_MMXEXT);
}
static void MC_put_x_8_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put2_8 (height, dest, ref, stride, 1, CPU_MMXEXT);
}
static void MC_avg_y_16_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg2_16 (height, dest, ref, stride, stride, CPU_MMXEXT);
}
static void MC_avg_y_8_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg2_8 (height, dest, ref, stride, stride, CPU_MMXEXT);
}
static void MC_put_y_16_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put2_16 (height, dest, ref, stride, stride, CPU_MMXEXT);
}
static void MC_put_y_8_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put2_8 (height, dest, ref, stride, stride, CPU_MMXEXT);
}
static void MC_avg_xy_16_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg4_16 (height, dest, ref, stride, CPU_MMXEXT);
}
static void MC_avg_xy_8_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg4_8 (height, dest, ref, stride, CPU_MMXEXT);
}
static void MC_put_xy_16_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put4_16 (height, dest, ref, stride, CPU_MMXEXT);
}
static void MC_put_xy_8_mmxext (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put4_8 (height, dest, ref, stride, CPU_MMXEXT);
}
MPEG2_MC_EXTERN (mmxext)
static void MC_avg_o_16_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg1_16 (height, dest, ref, stride, CPU_3DNOW);
}
static void MC_avg_o_8_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg1_8 (height, dest, ref, stride, CPU_3DNOW);
}
static void MC_put_o_16_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put1_16 (height, dest, ref, stride);
}
static void MC_put_o_8_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put1_8 (height, dest, ref, stride);
}
static void MC_avg_x_16_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg2_16 (height, dest, ref, stride, 1, CPU_3DNOW);
}
static void MC_avg_x_8_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg2_8 (height, dest, ref, stride, 1, CPU_3DNOW);
}
static void MC_put_x_16_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put2_16 (height, dest, ref, stride, 1, CPU_3DNOW);
}
static void MC_put_x_8_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put2_8 (height, dest, ref, stride, 1, CPU_3DNOW);
}
static void MC_avg_y_16_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg2_16 (height, dest, ref, stride, stride, CPU_3DNOW);
}
static void MC_avg_y_8_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg2_8 (height, dest, ref, stride, stride, CPU_3DNOW);
}
static void MC_put_y_16_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put2_16 (height, dest, ref, stride, stride, CPU_3DNOW);
}
static void MC_put_y_8_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put2_8 (height, dest, ref, stride, stride, CPU_3DNOW);
}
static void MC_avg_xy_16_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg4_16 (height, dest, ref, stride, CPU_3DNOW);
}
static void MC_avg_xy_8_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_avg4_8 (height, dest, ref, stride, CPU_3DNOW);
}
static void MC_put_xy_16_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put4_16 (height, dest, ref, stride, CPU_3DNOW);
}
static void MC_put_xy_8_3dnow (uint8_t * dest, const uint8_t * ref,
int stride, int height)
{
MC_put4_8 (height, dest, ref, stride, CPU_3DNOW);
}
MPEG2_MC_EXTERN (3dnow)
/* $Id:$
* mpeg2.h
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#ifndef MPEG2_H
#define MPEG2_H
#define MPEG2_VERSION(a,b,c) (((a)<<16)|((b)<<8)|(c))
#define MPEG2_RELEASE MPEG2_VERSION (0, 4, 0) /* 0.4.0 */
#define SEQ_FLAG_MPEG2 1
#define SEQ_FLAG_CONSTRAINED_PARAMETERS 2
#define SEQ_FLAG_PROGRESSIVE_SEQUENCE 4
#define SEQ_FLAG_LOW_DELAY 8
#define SEQ_FLAG_COLOUR_DESCRIPTION 16
#define SEQ_MASK_VIDEO_FORMAT 0xe0
#define SEQ_VIDEO_FORMAT_COMPONENT 0
#define SEQ_VIDEO_FORMAT_PAL 0x20
#define SEQ_VIDEO_FORMAT_NTSC 0x40
#define SEQ_VIDEO_FORMAT_SECAM 0x60
#define SEQ_VIDEO_FORMAT_MAC 0x80
#define SEQ_VIDEO_FORMAT_UNSPECIFIED 0xa0
typedef struct mpeg2_sequence_s
{
unsigned int width, height;
unsigned int chroma_width, chroma_height;
unsigned int byte_rate;
unsigned int vbv_buffer_size;
uint32_t flags;
unsigned int picture_width, picture_height;
unsigned int display_width, display_height;
unsigned int pixel_width, pixel_height;
unsigned int frame_period;
uint8_t profile_level_id;
uint8_t colour_primaries;
uint8_t transfer_characteristics;
uint8_t matrix_coefficients;
int aspect_ratio_information;
} mpeg2_sequence_t;
#define GOP_FLAG_DROP_FRAME 1
#define GOP_FLAG_BROKEN_LINK 2
#define GOP_FLAG_CLOSED_GOP 4
typedef struct mpeg2_gop_s
{
uint8_t hours;
uint8_t minutes;
uint8_t seconds;
uint8_t pictures;
uint32_t flags;
} mpeg2_gop_t;
#define PIC_MASK_CODING_TYPE 7
#define PIC_FLAG_CODING_TYPE_I 1
#define PIC_FLAG_CODING_TYPE_P 2
#define PIC_FLAG_CODING_TYPE_B 3
#define PIC_FLAG_CODING_TYPE_D 4
#define PIC_FLAG_TOP_FIELD_FIRST 8
#define PIC_FLAG_PROGRESSIVE_FRAME 16
#define PIC_FLAG_COMPOSITE_DISPLAY 32
#define PIC_FLAG_SKIP 64
#define PIC_FLAG_TAGS 128
#define PIC_MASK_COMPOSITE_DISPLAY 0xfffff000
typedef struct mpeg2_picture_s
{
unsigned int temporal_reference;
unsigned int nb_fields;
uint32_t tag, tag2;
uint32_t flags;
struct {
int x, y;
} display_offset[3];
} mpeg2_picture_t;
typedef struct mpeg2_fbuf_s
{
uint8_t * buf[3];
void * id;
} mpeg2_fbuf_t;
typedef struct mpeg2_info_s
{
const mpeg2_sequence_t * sequence;
const mpeg2_gop_t * gop;
const mpeg2_picture_t * current_picture;
const mpeg2_picture_t * current_picture_2nd;
const mpeg2_fbuf_t * current_fbuf;
const mpeg2_picture_t * display_picture;
const mpeg2_picture_t * display_picture_2nd;
const mpeg2_fbuf_t * display_fbuf;
const mpeg2_fbuf_t * discard_fbuf;
const uint8_t * user_data;
unsigned int user_data_len;
} mpeg2_info_t;
typedef struct mpeg2dec_s mpeg2dec_t;
typedef struct mpeg2_decoder_s mpeg2_decoder_t;
typedef enum
{
STATE_BUFFER = 0,
STATE_SEQUENCE = 1,
STATE_SEQUENCE_REPEATED = 2,
STATE_GOP = 3,
STATE_PICTURE = 4,
STATE_SLICE_1ST = 5,
STATE_PICTURE_2ND = 6,
STATE_SLICE = 7,
STATE_END = 8,
STATE_INVALID = 9,
STATE_INVALID_END = 10
} mpeg2_state_t;
typedef struct mpeg2_convert_init_s
{
unsigned int id_size;
unsigned int buf_size[3];
void (* start) (void * id, const mpeg2_fbuf_t * fbuf,
const mpeg2_picture_t * picture, const mpeg2_gop_t * gop);
void (* copy) (void * id, uint8_t * const * src, unsigned int v_offset);
} mpeg2_convert_init_t;
typedef enum
{
MPEG2_CONVERT_SET = 0,
MPEG2_CONVERT_STRIDE = 1,
MPEG2_CONVERT_START = 2
} mpeg2_convert_stage_t;
typedef int mpeg2_convert_t (int stage, void * id,
const mpeg2_sequence_t * sequence, int stride,
uint32_t accel, void * arg,
mpeg2_convert_init_t * result);
int mpeg2_convert (mpeg2dec_t * mpeg2dec, mpeg2_convert_t convert, void * arg);
int mpeg2_stride (mpeg2dec_t * mpeg2dec, int stride);
void mpeg2_set_buf (mpeg2dec_t * mpeg2dec, uint8_t * buf[3], void * id);
void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf);
#define MPEG2_ACCEL_X86_MMX 1
#define MPEG2_ACCEL_X86_3DNOW 2
#define MPEG2_ACCEL_X86_MMXEXT 4
#define MPEG2_ACCEL_PPC_ALTIVEC 1
#define MPEG2_ACCEL_ALPHA 1
#define MPEG2_ACCEL_ALPHA_MVI 2
#define MPEG2_ACCEL_SPARC_VIS 1
#define MPEG2_ACCEL_SPARC_VIS2 2
#define MPEG2_ACCEL_DETECT 0x80000000
uint32_t mpeg2_accel (uint32_t accel);
mpeg2dec_t * mpeg2_init (void);
const mpeg2_info_t * mpeg2_info (mpeg2dec_t * mpeg2dec);
void mpeg2_close (mpeg2dec_t * mpeg2dec);
void mpeg2_buffer (mpeg2dec_t * mpeg2dec, uint8_t * start, uint8_t * end);
int mpeg2_getpos (mpeg2dec_t * mpeg2dec);
mpeg2_state_t mpeg2_parse (mpeg2dec_t * mpeg2dec);
void mpeg2_reset (mpeg2dec_t * mpeg2dec, int full_reset);
void mpeg2_skip (mpeg2dec_t * mpeg2dec, int skip);
void mpeg2_slice_region (mpeg2dec_t * mpeg2dec, int start, int end);
void mpeg2_tag_picture (mpeg2dec_t * mpeg2dec, uint32_t tag, uint32_t tag2);
void mpeg2_init_fbuf (mpeg2_decoder_t * decoder, uint8_t * current_fbuf[3],
uint8_t * forward_fbuf[3], uint8_t * backward_fbuf[3]);
typedef enum
{
MPEG2_ALLOC_MPEG2DEC = 0,
MPEG2_ALLOC_CHUNK = 1,
MPEG2_ALLOC_YUV = 2,
MPEG2_ALLOC_CONVERT_ID = 3,
MPEG2_ALLOC_CONVERTED = 4
} mpeg2_alloc_t;
void * mpeg2_malloc (unsigned size, mpeg2_alloc_t reason);
void mpeg2_free (void * buf);
void mpeg2_malloc_hooks (void * malloc (unsigned, mpeg2_alloc_t),
int free (void *));
#endif /* MPEG2_H */
/* $Id:$
* mpeg2_internal.h
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
/* macroblock modes */
#define MACROBLOCK_INTRA 1
#define MACROBLOCK_PATTERN 2
#define MACROBLOCK_MOTION_BACKWARD 4
#define MACROBLOCK_MOTION_FORWARD 8
#define MACROBLOCK_QUANT 16
#define DCT_TYPE_INTERLACED 32
/* motion_type */
#define MOTION_TYPE_SHIFT 6
#define MC_FIELD 1
#define MC_FRAME 2
#define MC_16X8 2
#define MC_DMV 3
/* picture structure */
#define TOP_FIELD 1
#define BOTTOM_FIELD 2
#define FRAME_PICTURE 3
/* picture coding type */
#define I_TYPE 1
#define P_TYPE 2
#define B_TYPE 3
#define D_TYPE 4
typedef void mpeg2_mc_fct (uint8_t *, const uint8_t *, int, int);
typedef struct
{
uint8_t * ref[2][3];
uint8_t ** ref2[2];
int pmv[2][2];
int f_code[2];
} motion_t;
typedef void motion_parser_t( mpeg2_decoder_t * decoder,
motion_t * motion,
mpeg2_mc_fct * const * table );
struct mpeg2_decoder_s
{
/* first, state that carries information from one macroblock to the */
/* next inside a slice, and is never used outside of mpeg2_slice() */
/* bit parsing stuff */
uint32_t bitstream_buf; /* current 32 bit working set */
int bitstream_bits; /* used bits in working set */
const uint8_t * bitstream_ptr; /* buffer with stream data */
uint8_t * dest[3];
int offset;
int stride;
int uv_stride;
int slice_stride;
int slice_uv_stride;
int stride_frame;
unsigned int limit_x;
unsigned int limit_y_16;
unsigned int limit_y_8;
unsigned int limit_y;
/* Motion vectors */
/* The f_ and b_ correspond to the forward and backward motion */
/* predictors */
motion_t b_motion;
motion_t f_motion;
motion_parser_t * motion_parser[5];
/* predictor for DC coefficients in intra blocks */
int16_t dc_dct_pred[3];
/* DCT coefficients */
int16_t DCTblock[64] ATTR_ALIGN(64);
uint8_t * picture_dest[3];
void (* convert) (void * convert_id, uint8_t * const * src,
unsigned int v_offset);
void * convert_id;
int dmv_offset;
unsigned int v_offset;
/* now non-slice-specific information */
/* sequence header stuff */
uint16_t * quantizer_matrix[4];
uint16_t (* chroma_quantizer[2])[64];
uint16_t quantizer_prescale[4][32][64];
int load_intra_quantizer_matrix;
int load_non_intra_quantizer_matrix;
/* The width and height of the picture snapped to macroblock units */
int width;
int height;
int vertical_position_extension;
int chroma_format;
/* picture header stuff */
/* what type of picture this is (I, P, B, D) */
int coding_type;
/* picture coding extension stuff */
/* quantization factor for intra dc coefficients */
int intra_dc_precision;
/* top/bottom/both fields */
int picture_structure;
/* bool to indicate all predictions are frame based */
int frame_pred_frame_dct;
/* bool to indicate whether intra blocks have motion vectors */
/* (for concealment) */
int concealment_motion_vectors;
/* bit to indicate which quantization table to use */
int q_scale_type;
/* bool to use different vlc tables */
int intra_vlc_format;
/* used for DMV MC */
int top_field_first;
/* stuff derived from bitstream */
/* pointer to the zigzag scan we're supposed to be using */
const uint8_t * scan;
int second_field;
int mpeg1;
int aspect_ratio_information;
int progressive_sequence;
};
typedef struct
{
mpeg2_fbuf_t fbuf;
} fbuf_alloc_t;
struct mpeg2dec_s
{
mpeg2_decoder_t decoder;
mpeg2_info_t info;
uint32_t shift;
int is_display_initialized;
mpeg2_state_t (* action) (struct mpeg2dec_s * mpeg2dec);
mpeg2_state_t state;
uint32_t ext_state;
/* allocated in init - gcc has problems allocating such big structures */
uint8_t * chunk_buffer;
/* pointer to start of the current chunk */
uint8_t * chunk_start;
/* pointer to current position in chunk_buffer */
uint8_t * chunk_ptr;
uint32_t chunk_size;
/* last start code ? */
uint8_t code;
uint8_t prev_code;
/* picture tags */
uint32_t tag_current, tag2_current, tag_previous, tag2_previous;
int num_tags;
int bytes_since_tag;
int first;
int alloc_index_user;
int alloc_index;
uint8_t first_decode_slice;
uint8_t nb_decode_slices;
unsigned int user_data_len;
mpeg2_sequence_t new_sequence;
mpeg2_sequence_t sequence;
mpeg2_gop_t new_gop;
mpeg2_gop_t gop;
mpeg2_picture_t new_picture;
mpeg2_picture_t pictures[4];
mpeg2_picture_t * picture;
/*const*/ mpeg2_fbuf_t * fbuf[3]; /* 0: current fbuf, 1-2: prediction fbufs */
fbuf_alloc_t fbuf_alloc[3];
int custom_fbuf;
uint8_t * yuv_buf[3][3];
int yuv_index;
mpeg2_convert_t * convert;
void * convert_arg;
unsigned int convert_id_size;
int convert_stride;
void (* convert_start) (void * id, const mpeg2_fbuf_t * fbuf,
const mpeg2_picture_t * picture,
const mpeg2_gop_t * gop);
uint8_t * buf_start;
uint8_t * buf_end;
int16_t display_offset_x, display_offset_y;
int copy_matrix;
int8_t q_scale_type, scaled[4];
uint8_t quantizer_matrix[4][64];
uint8_t new_quantizer_matrix[4][64];
/* a spu decoder for possible closed captions */
//spu_decoder_t *cc_dec;
int xvmc_last_slice_code;
unsigned xxmc_mb_pic_height;
void *ptr_forward_ref_picture;
void *ptr_backward_ref_picture;
};
typedef struct
{
#ifdef ARCH_PPC
uint8_t regv[12*16];
#endif
int dummy;
} cpu_state_t;
/* cpu_accel.c */
uint32_t mpeg2_detect_accel (void);
/* cpu_state.c */
void mpeg2_cpu_state_init (uint32_t accel);
/* decode.c */
mpeg2_state_t mpeg2_seek_header (mpeg2dec_t * mpeg2dec);
mpeg2_state_t mpeg2_parse_header (mpeg2dec_t * mpeg2dec);
/* header.c */
extern uint8_t mpeg2_scan_norm[64];
extern uint8_t mpeg2_scan_alt[64];
void mpeg2_header_state_init (mpeg2dec_t * mpeg2dec);
void mpeg2_reset_info (mpeg2_info_t * info);
int mpeg2_header_sequence (mpeg2dec_t * mpeg2dec);
int mpeg2_header_gop (mpeg2dec_t * mpeg2dec);
mpeg2_state_t mpeg2_header_picture_start (mpeg2dec_t * mpeg2dec);
int mpeg2_header_picture (mpeg2dec_t * mpeg2dec);
int mpeg2_header_extension (mpeg2dec_t * mpeg2dec);
int mpeg2_header_user_data (mpeg2dec_t * mpeg2dec);
void mpeg2_header_sequence_finalize (mpeg2dec_t * mpeg2dec);
void mpeg2_header_gop_finalize (mpeg2dec_t * mpeg2dec);
void mpeg2_header_picture_finalize (mpeg2dec_t * mpeg2dec, uint32_t accels);
mpeg2_state_t mpeg2_header_slice_start (mpeg2dec_t * mpeg2dec);
mpeg2_state_t mpeg2_header_end (mpeg2dec_t * mpeg2dec);
void mpeg2_set_fbuf (mpeg2dec_t * mpeg2dec, int b_type);
/* motion_comp.c */
void mpeg2_mc_init (uint32_t accel);
typedef struct {
mpeg2_mc_fct * put [8];
mpeg2_mc_fct * avg [8];
} mpeg2_mc_t;
#define MPEG2_MC_EXTERN(x) mpeg2_mc_t mpeg2_mc_##x = { \
{MC_put_o_16_##x, MC_put_x_16_##x, MC_put_y_16_##x, MC_put_xy_16_##x, \
MC_put_o_8_##x, MC_put_x_8_##x, MC_put_y_8_##x, MC_put_xy_8_##x}, \
{MC_avg_o_16_##x, MC_avg_x_16_##x, MC_avg_y_16_##x, MC_avg_xy_16_##x, \
MC_avg_o_8_##x, MC_avg_x_8_##x, MC_avg_y_8_##x, MC_avg_xy_8_##x} \
};
extern mpeg2_mc_t mpeg2_mc_c;
extern mpeg2_mc_t mpeg2_mc_mmx;
extern mpeg2_mc_t mpeg2_mc_mmxext;
extern mpeg2_mc_t mpeg2_mc_3dnow;
extern mpeg2_mc_t mpeg2_mc_altivec;
extern mpeg2_mc_t mpeg2_mc_alpha;
extern mpeg2_mc_t mpeg2_mc_vis;
/* $Id:$
* slice.c
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 2003 Peter Gubanov <peter@elecard.net.ru>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#include "xxmc-config.h"
#include <inttypes.h>
#include "mpeg2.h"
#include "attributes.h"
#include "mpeg2_internal.h"
extern mpeg2_mc_t mpeg2_mc;
extern void (* mpeg2_cpu_state_save) (cpu_state_t * state);
extern void (* mpeg2_cpu_state_restore) (cpu_state_t * state);
#include "vlc.h"
static inline int get_motion_delta( mpeg2_decoder_t * const decoder,
const int f_code )
{
#define bit_buf (decoder->bitstream_buf)
#define bits (decoder->bitstream_bits)
#define bit_ptr (decoder->bitstream_ptr)
int delta;
int sign;
const MVtab * tab;
if( bit_buf & 0x80000000 )
{
DUMPBITS (bit_buf, bits, 1);
return 0;
}
else if (bit_buf >= 0x0c000000)
{
tab = MV_4 + UBITS (bit_buf, 4);
delta = (tab->delta << f_code) + 1;
bits += tab->len + f_code + 1;
bit_buf <<= tab->len;
sign = SBITS (bit_buf, 1);
bit_buf <<= 1;
if (f_code)
delta += UBITS (bit_buf, f_code);
bit_buf <<= f_code;
return (delta ^ sign) - sign;
}
else
{
tab = MV_10 + UBITS (bit_buf, 10);
delta = (tab->delta << f_code) + 1;
bits += tab->len + 1;
bit_buf <<= tab->len;
sign = SBITS (bit_buf, 1);
bit_buf <<= 1;
if (f_code)
{
NEEDBITS (bit_buf, bits, bit_ptr);
delta += UBITS (bit_buf, f_code);
DUMPBITS (bit_buf, bits, f_code);
}
return (delta ^ sign) - sign;
}
#undef bit_buf
#undef bits
#undef bit_ptr
}
static inline int bound_motion_vector (const int vector, const int f_code)
{
return ((int32_t)vector << (27 - f_code)) >> (27 - f_code);
}
static inline int get_dmv (mpeg2_decoder_t * const decoder)
{
#define bit_buf (decoder->bitstream_buf)
#define bits (decoder->bitstream_bits)
#define bit_ptr (decoder->bitstream_ptr)
const DMVtab * tab;
tab = DMV_2 + UBITS (bit_buf, 2);
DUMPBITS (bit_buf, bits, tab->len);
return tab->dmv;
#undef bit_buf
#undef bits
#undef bit_ptr
}
#define MOTION_420(table,ref,motion_x,motion_y,size,y) \
pos_x = 2 * decoder->offset + motion_x; \
pos_y = 2 * decoder->v_offset + motion_y + 2 * y; \
if (unlikely (pos_x > decoder->limit_x)) { \
pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \
motion_x = pos_x - 2 * decoder->offset; \
} \
if (unlikely (pos_y > decoder->limit_y_ ## size)) { \
pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y_ ## size; \
motion_y = pos_y - 2 * decoder->v_offset - 2 * y; \
} \
xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \
table[xy_half] (decoder->dest[0] + y * decoder->stride + decoder->offset, \
ref[0] + (pos_x >> 1) + (pos_y >> 1) * decoder->stride, \
decoder->stride, size); \
motion_x /= 2; motion_y /= 2; \
xy_half = ((motion_y & 1) << 1) | (motion_x & 1); \
offset = (((decoder->offset + motion_x) >> 1) + \
((((decoder->v_offset + motion_y) >> 1) + y/2) * \
decoder->uv_stride)); \
table[4+xy_half] (decoder->dest[1] + y/2 * decoder->uv_stride + \
(decoder->offset >> 1), ref[1] + offset, \
decoder->uv_stride, size/2); \
table[4+xy_half] (decoder->dest[2] + y/2 * decoder->uv_stride + \
(decoder->offset >> 1), ref[2] + offset, \
decoder->uv_stride, size/2)
#define MOTION_FIELD_420(table,ref,motion_x,motion_y,dest_field,op,src_field) \
pos_x = 2 * decoder->offset + motion_x; \
pos_y = decoder->v_offset + motion_y; \
if (unlikely (pos_x > decoder->limit_x)) { \
pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \
motion_x = pos_x - 2 * decoder->offset; \
} \
if (unlikely (pos_y > decoder->limit_y)) { \
pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \
motion_y = pos_y - decoder->v_offset; \
} \
xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \
table[xy_half] (decoder->dest[0] + dest_field * decoder->stride + \
decoder->offset, \
(ref[0] + (pos_x >> 1) + \
((pos_y op) + src_field) * decoder->stride), \
2 * decoder->stride, 8); \
motion_x /= 2; motion_y /= 2; \
xy_half = ((motion_y & 1) << 1) | (motion_x & 1); \
offset = (((decoder->offset + motion_x) >> 1) + \
(((decoder->v_offset >> 1) + (motion_y op) + src_field) * \
decoder->uv_stride)); \
table[4+xy_half] (decoder->dest[1] + dest_field * decoder->uv_stride + \
(decoder->offset >> 1), ref[1] + offset, \
2 * decoder->uv_stride, 4); \
table[4+xy_half] (decoder->dest[2] + dest_field * decoder->uv_stride + \
(decoder->offset >> 1), ref[2] + offset, \
2 * decoder->uv_stride, 4)
#define MOTION_DMV_420(table,ref,motion_x,motion_y) \
pos_x = 2 * decoder->offset + motion_x; \
pos_y = decoder->v_offset + motion_y; \
if (unlikely (pos_x > decoder->limit_x)) { \
pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \
motion_x = pos_x - 2 * decoder->offset; \
} \
if (unlikely (pos_y > decoder->limit_y)) { \
pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \
motion_y = pos_y - decoder->v_offset; \
} \
xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \
offset = (pos_x >> 1) + (pos_y & ~1) * decoder->stride; \
table[xy_half] (decoder->dest[0] + decoder->offset, \
ref[0] + offset, 2 * decoder->stride, 8); \
table[xy_half] (decoder->dest[0] + decoder->stride + decoder->offset, \
ref[0] + decoder->stride + offset, \
2 * decoder->stride, 8); \
motion_x /= 2; motion_y /= 2; \
xy_half = ((motion_y & 1) << 1) | (motion_x & 1); \
offset = (((decoder->offset + motion_x) >> 1) + \
(((decoder->v_offset >> 1) + (motion_y & ~1)) * \
decoder->uv_stride)); \
table[4+xy_half] (decoder->dest[1] + (decoder->offset >> 1), \
ref[1] + offset, 2 * decoder->uv_stride, 4); \
table[4+xy_half] (decoder->dest[1] + decoder->uv_stride + \
(decoder->offset >> 1), \
ref[1] + decoder->uv_stride + offset, \
2 * decoder->uv_stride, 4); \
table[4+xy_half] (decoder->dest[2] + (decoder->offset >> 1), \
ref[2] + offset, 2 * decoder->uv_stride, 4); \
table[4+xy_half] (decoder->dest[2] + decoder->uv_stride + \
(decoder->offset >> 1), \
ref[2] + decoder->uv_stride + offset, \
2 * decoder->uv_stride, 4)
#define MOTION_ZERO_420(table,ref) \
table[0] (decoder->dest[0] + decoder->offset, \
(ref[0] + decoder->offset + \
decoder->v_offset * decoder->stride), decoder->stride, 16); \
offset = ((decoder->offset >> 1) + \
(decoder->v_offset >> 1) * decoder->uv_stride); \
table[4] (decoder->dest[1] + (decoder->offset >> 1), \
ref[1] + offset, decoder->uv_stride, 8); \
table[4] (decoder->dest[2] + (decoder->offset >> 1), \
ref[2] + offset, decoder->uv_stride, 8)
#define MOTION_422(table,ref,motion_x,motion_y,size,y) \
pos_x = 2 * decoder->offset + motion_x; \
pos_y = 2 * decoder->v_offset + motion_y + 2 * y; \
if (unlikely (pos_x > decoder->limit_x)) { \
pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \
motion_x = pos_x - 2 * decoder->offset; \
} \
if (unlikely (pos_y > decoder->limit_y_ ## size)) { \
pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y_ ## size; \
motion_y = pos_y - 2 * decoder->v_offset - 2 * y; \
} \
xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \
offset = (pos_x >> 1) + (pos_y >> 1) * decoder->stride; \
table[xy_half] (decoder->dest[0] + y * decoder->stride + decoder->offset, \
ref[0] + offset, decoder->stride, size); \
offset = (offset + (motion_x & (motion_x < 0))) >> 1; \
motion_x /= 2; \
xy_half = ((pos_y & 1) << 1) | (motion_x & 1); \
table[4+xy_half] (decoder->dest[1] + y * decoder->uv_stride + \
(decoder->offset >> 1), ref[1] + offset, \
decoder->uv_stride, size); \
table[4+xy_half] (decoder->dest[2] + y * decoder->uv_stride + \
(decoder->offset >> 1), ref[2] + offset, \
decoder->uv_stride, size)
#define MOTION_FIELD_422(table,ref,motion_x,motion_y,dest_field,op,src_field) \
pos_x = 2 * decoder->offset + motion_x; \
pos_y = decoder->v_offset + motion_y; \
if (unlikely (pos_x > decoder->limit_x)) { \
pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \
motion_x = pos_x - 2 * decoder->offset; \
} \
if (unlikely (pos_y > decoder->limit_y)) { \
pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \
motion_y = pos_y - decoder->v_offset; \
} \
xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \
offset = (pos_x >> 1) + ((pos_y op) + src_field) * decoder->stride; \
table[xy_half] (decoder->dest[0] + dest_field * decoder->stride + \
decoder->offset, ref[0] + offset, \
2 * decoder->stride, 8); \
offset = (offset + (motion_x & (motion_x < 0))) >> 1; \
motion_x /= 2; \
xy_half = ((pos_y & 1) << 1) | (motion_x & 1); \
table[4+xy_half] (decoder->dest[1] + dest_field * decoder->uv_stride + \
(decoder->offset >> 1), ref[1] + offset, \
2 * decoder->uv_stride, 8); \
table[4+xy_half] (decoder->dest[2] + dest_field * decoder->uv_stride + \
(decoder->offset >> 1), ref[2] + offset, \
2 * decoder->uv_stride, 8)
#define MOTION_DMV_422(table,ref,motion_x,motion_y) \
pos_x = 2 * decoder->offset + motion_x; \
pos_y = decoder->v_offset + motion_y; \
if (unlikely (pos_x > decoder->limit_x)) { \
pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \
motion_x = pos_x - 2 * decoder->offset; \
} \
if (unlikely (pos_y > decoder->limit_y)) { \
pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \
motion_y = pos_y - decoder->v_offset; \
} \
xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \
offset = (pos_x >> 1) + (pos_y & ~1) * decoder->stride; \
table[xy_half] (decoder->dest[0] + decoder->offset, \
ref[0] + offset, 2 * decoder->stride, 8); \
table[xy_half] (decoder->dest[0] + decoder->stride + decoder->offset, \
ref[0] + decoder->stride + offset, \
2 * decoder->stride, 8); \
offset = (offset + (motion_x & (motion_x < 0))) >> 1; \
motion_x /= 2; \
xy_half = ((pos_y & 1) << 1) | (motion_x & 1); \
table[4+xy_half] (decoder->dest[1] + (decoder->offset >> 1), \
ref[1] + offset, 2 * decoder->uv_stride, 8); \
table[4+xy_half] (decoder->dest[1] + decoder->uv_stride + \
(decoder->offset >> 1), \
ref[1] + decoder->uv_stride + offset, \
2 * decoder->uv_stride, 8); \
table[4+xy_half] (decoder->dest[2] + (decoder->offset >> 1), \
ref[2] + offset, 2 * decoder->uv_stride, 8); \
table[4+xy_half] (decoder->dest[2] + decoder->uv_stride + \
(decoder->offset >> 1), \
ref[2] + decoder->uv_stride + offset, \
2 * decoder->uv_stride, 8)
#define MOTION_ZERO_422(table,ref) \
offset = decoder->offset + decoder->v_offset * decoder->stride; \
table[0] (decoder->dest[0] + decoder->offset, \
ref[0] + offset, decoder->stride, 16); \
offset >>= 1; \
table[4] (decoder->dest[1] + (decoder->offset >> 1), \
ref[1] + offset, decoder->uv_stride, 16); \
table[4] (decoder->dest[2] + (decoder->offset >> 1), \
ref[2] + offset, decoder->uv_stride, 16)
#define MOTION_444(table,ref,motion_x,motion_y,size,y) \
pos_x = 2 * decoder->offset + motion_x; \
pos_y = 2 * decoder->v_offset + motion_y + 2 * y; \
if (unlikely (pos_x > decoder->limit_x)) { \
pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \
motion_x = pos_x - 2 * decoder->offset; \
} \
if (unlikely (pos_y > decoder->limit_y_ ## size)) { \
pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y_ ## size; \
motion_y = pos_y - 2 * decoder->v_offset - 2 * y; \
} \
xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \
offset = (pos_x >> 1) + (pos_y >> 1) * decoder->stride; \
table[xy_half] (decoder->dest[0] + y * decoder->stride + decoder->offset, \
ref[0] + offset, decoder->stride, size); \
table[xy_half] (decoder->dest[1] + y * decoder->stride + decoder->offset, \
ref[1] + offset, decoder->stride, size); \
table[xy_half] (decoder->dest[2] + y * decoder->stride + decoder->offset, \
ref[2] + offset, decoder->stride, size)
#define MOTION_FIELD_444(table,ref,motion_x,motion_y,dest_field,op,src_field) \
pos_x = 2 * decoder->offset + motion_x; \
pos_y = decoder->v_offset + motion_y; \
if (unlikely (pos_x > decoder->limit_x)) { \
pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \
motion_x = pos_x - 2 * decoder->offset; \
} \
if (unlikely (pos_y > decoder->limit_y)) { \
pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \
motion_y = pos_y - decoder->v_offset; \
} \
xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \
offset = (pos_x >> 1) + ((pos_y op) + src_field) * decoder->stride; \
table[xy_half] (decoder->dest[0] + dest_field * decoder->stride + \
decoder->offset, ref[0] + offset, \
2 * decoder->stride, 8); \
table[xy_half] (decoder->dest[1] + dest_field * decoder->stride + \
decoder->offset, ref[1] + offset, \
2 * decoder->stride, 8); \
table[xy_half] (decoder->dest[2] + dest_field * decoder->stride + \
decoder->offset, ref[2] + offset, \
2 * decoder->stride, 8)
#define MOTION_DMV_444(table,ref,motion_x,motion_y) \
pos_x = 2 * decoder->offset + motion_x; \
pos_y = decoder->v_offset + motion_y; \
if (unlikely (pos_x > decoder->limit_x)) { \
pos_x = ((int)pos_x < 0) ? 0 : decoder->limit_x; \
motion_x = pos_x - 2 * decoder->offset; \
} \
if (unlikely (pos_y > decoder->limit_y)) { \
pos_y = ((int)pos_y < 0) ? 0 : decoder->limit_y; \
motion_y = pos_y - decoder->v_offset; \
} \
xy_half = ((pos_y & 1) << 1) | (pos_x & 1); \
offset = (pos_x >> 1) + (pos_y & ~1) * decoder->stride; \
table[xy_half] (decoder->dest[0] + decoder->offset, \
ref[0] + offset, 2 * decoder->stride, 8); \
table[xy_half] (decoder->dest[0] + decoder->stride + decoder->offset, \
ref[0] + decoder->stride + offset, \
2 * decoder->stride, 8); \
table[xy_half] (decoder->dest[1] + decoder->offset, \
ref[1] + offset, 2 * decoder->stride, 8); \
table[xy_half] (decoder->dest[1] + decoder->stride + decoder->offset, \
ref[1] + decoder->stride + offset, \
2 * decoder->stride, 8); \
table[xy_half] (decoder->dest[2] + decoder->offset, \
ref[2] + offset, 2 * decoder->stride, 8); \
table[xy_half] (decoder->dest[2] + decoder->stride + decoder->offset, \
ref[2] + decoder->stride + offset, \
2 * decoder->stride, 8)
#define MOTION_ZERO_444(table,ref) \
offset = decoder->offset + decoder->v_offset * decoder->stride; \
table[0] (decoder->dest[0] + decoder->offset, \
ref[0] + offset, decoder->stride, 16); \
table[4] (decoder->dest[1] + decoder->offset, \
ref[1] + offset, decoder->stride, 16); \
table[4] (decoder->dest[2] + (decoder->offset >> 1), \
ref[2] + offset, decoder->stride, 16)
#define bit_buf (decoder->bitstream_buf)
#define bits (decoder->bitstream_bits)
#define bit_ptr (decoder->bitstream_ptr)
static void motion_mp1 (mpeg2_decoder_t * const decoder,
motion_t * const motion,
mpeg2_mc_fct * const * const table)
{
int motion_x, motion_y;
unsigned int pos_x, pos_y, xy_half, offset;
NEEDBITS (bit_buf, bits, bit_ptr);
motion_x = (motion->pmv[0][0] +
(get_motion_delta( decoder,
motion->f_code[0] ) << motion->f_code[1]));
motion_x = bound_motion_vector( motion_x,
motion->f_code[0] + motion->f_code[1]);
motion->pmv[0][0] = motion_x;
NEEDBITS (bit_buf, bits, bit_ptr);
motion_y = (motion->pmv[0][1] +
(get_motion_delta( decoder,
motion->f_code[0]) << motion->f_code[1]));
motion_y = bound_motion_vector( motion_y,
motion->f_code[0] + motion->f_code[1]);
motion->pmv[0][1] = motion_y;
MOTION_420 (table, motion->ref[0], motion_x, motion_y, 16, 0);
}
#define MOTION_FUNCTIONS(FORMAT,MOTION,MOTION_FIELD,MOTION_DMV,MOTION_ZERO) \
\
static void motion_fr_frame_##FORMAT (mpeg2_decoder_t * const decoder, \
motion_t * const motion, \
mpeg2_mc_fct * const * const table) \
{ \
int motion_x, motion_y; \
unsigned int pos_x, pos_y, xy_half, offset; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \
motion->f_code[0]); \
motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \
motion->pmv[1][0] = motion->pmv[0][0] = motion_x; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
motion_y = motion->pmv[0][1] + get_motion_delta (decoder, \
motion->f_code[1]); \
motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \
motion->pmv[1][1] = motion->pmv[0][1] = motion_y; \
\
MOTION (table, motion->ref[0], motion_x, motion_y, 16, 0); \
} \
\
static void motion_fr_field_##FORMAT (mpeg2_decoder_t * const decoder, \
motion_t * const motion, \
mpeg2_mc_fct * const * const table) \
{ \
int motion_x, motion_y, field; \
unsigned int pos_x, pos_y, xy_half, offset; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
field = UBITS (bit_buf, 1); \
DUMPBITS (bit_buf, bits, 1); \
\
motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \
motion->f_code[0]); \
motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \
motion->pmv[0][0] = motion_x; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
motion_y = ((motion->pmv[0][1] >> 1) + \
get_motion_delta (decoder, motion->f_code[1])); \
/* motion_y = bound_motion_vector (motion_y, motion->f_code[1]); */ \
motion->pmv[0][1] = motion_y << 1; \
\
MOTION_FIELD (table, motion->ref[0], motion_x, motion_y, 0, & ~1, field); \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
field = UBITS (bit_buf, 1); \
DUMPBITS (bit_buf, bits, 1); \
\
motion_x = motion->pmv[1][0] + get_motion_delta (decoder, \
motion->f_code[0]); \
motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \
motion->pmv[1][0] = motion_x; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
motion_y = ((motion->pmv[1][1] >> 1) + \
get_motion_delta (decoder, motion->f_code[1])); \
/* motion_y = bound_motion_vector (motion_y, motion->f_code[1]); */ \
motion->pmv[1][1] = motion_y << 1; \
\
MOTION_FIELD (table, motion->ref[0], motion_x, motion_y, 1, & ~1, field); \
} \
\
static void motion_fr_dmv_##FORMAT (mpeg2_decoder_t * const decoder, \
motion_t * const motion, \
mpeg2_mc_fct * const * const table) \
{ \
int motion_x, motion_y, dmv_x, dmv_y, m, other_x, other_y; \
unsigned int pos_x, pos_y, xy_half, offset; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \
motion->f_code[0]); \
motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \
motion->pmv[1][0] = motion->pmv[0][0] = motion_x; \
NEEDBITS (bit_buf, bits, bit_ptr); \
dmv_x = get_dmv (decoder); \
\
motion_y = ((motion->pmv[0][1] >> 1) + \
get_motion_delta (decoder, motion->f_code[1])); \
/* motion_y = bound_motion_vector (motion_y, motion->f_code[1]); */ \
motion->pmv[1][1] = motion->pmv[0][1] = motion_y << 1; \
dmv_y = get_dmv (decoder); \
\
m = decoder->top_field_first ? 1 : 3; \
other_x = ((motion_x * m + (motion_x > 0)) >> 1) + dmv_x; \
other_y = ((motion_y * m + (motion_y > 0)) >> 1) + dmv_y - 1; \
MOTION_FIELD (mpeg2_mc.put, motion->ref[0], other_x, other_y, 0, | 1, 0); \
\
m = decoder->top_field_first ? 3 : 1; \
other_x = ((motion_x * m + (motion_x > 0)) >> 1) + dmv_x; \
other_y = ((motion_y * m + (motion_y > 0)) >> 1) + dmv_y + 1; \
MOTION_FIELD (mpeg2_mc.put, motion->ref[0], other_x, other_y, 1, & ~1, 0);\
\
MOTION_DMV (mpeg2_mc.avg, motion->ref[0], motion_x, motion_y); \
} \
\
static void motion_reuse_##FORMAT (mpeg2_decoder_t * const decoder, \
motion_t * const motion, \
mpeg2_mc_fct * const * const table) \
{ \
int motion_x, motion_y; \
unsigned int pos_x, pos_y, xy_half, offset; \
\
motion_x = motion->pmv[0][0]; \
motion_y = motion->pmv[0][1]; \
\
MOTION (table, motion->ref[0], motion_x, motion_y, 16, 0); \
} \
\
static void motion_zero_##FORMAT (mpeg2_decoder_t * const decoder, \
motion_t * const motion, \
mpeg2_mc_fct * const * const table) \
{ \
unsigned int offset; \
\
motion->pmv[0][0] = motion->pmv[0][1] = 0; \
motion->pmv[1][0] = motion->pmv[1][1] = 0; \
\
MOTION_ZERO (table, motion->ref[0]); \
} \
\
static void motion_fi_field_##FORMAT (mpeg2_decoder_t * const decoder, \
motion_t * const motion, \
mpeg2_mc_fct * const * const table) \
{ \
int motion_x, motion_y; \
uint8_t ** ref_field; \
unsigned int pos_x, pos_y, xy_half, offset; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
ref_field = motion->ref2[UBITS (bit_buf, 1)]; \
DUMPBITS (bit_buf, bits, 1); \
\
motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \
motion->f_code[0]); \
motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \
motion->pmv[1][0] = motion->pmv[0][0] = motion_x; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
motion_y = motion->pmv[0][1] + get_motion_delta (decoder, \
motion->f_code[1]); \
motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \
motion->pmv[1][1] = motion->pmv[0][1] = motion_y; \
\
MOTION (table, ref_field, motion_x, motion_y, 16, 0); \
} \
\
static void motion_fi_16x8_##FORMAT (mpeg2_decoder_t * const decoder, \
motion_t * const motion, \
mpeg2_mc_fct * const * const table) \
{ \
int motion_x, motion_y; \
uint8_t ** ref_field; \
unsigned int pos_x, pos_y, xy_half, offset; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
ref_field = motion->ref2[UBITS (bit_buf, 1)]; \
DUMPBITS (bit_buf, bits, 1); \
\
motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \
motion->f_code[0]); \
motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \
motion->pmv[0][0] = motion_x; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
motion_y = motion->pmv[0][1] + get_motion_delta (decoder, \
motion->f_code[1]); \
motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \
motion->pmv[0][1] = motion_y; \
\
MOTION (table, ref_field, motion_x, motion_y, 8, 0); \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
ref_field = motion->ref2[UBITS (bit_buf, 1)]; \
DUMPBITS (bit_buf, bits, 1); \
\
motion_x = motion->pmv[1][0] + get_motion_delta (decoder, \
motion->f_code[0]); \
motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \
motion->pmv[1][0] = motion_x; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
motion_y = motion->pmv[1][1] + get_motion_delta (decoder, \
motion->f_code[1]); \
motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \
motion->pmv[1][1] = motion_y; \
\
MOTION (table, ref_field, motion_x, motion_y, 8, 8); \
} \
\
static void motion_fi_dmv_##FORMAT (mpeg2_decoder_t * const decoder, \
motion_t * const motion, \
mpeg2_mc_fct * const * const table) \
{ \
int motion_x, motion_y, other_x, other_y; \
unsigned int pos_x, pos_y, xy_half, offset; \
\
NEEDBITS (bit_buf, bits, bit_ptr); \
motion_x = motion->pmv[0][0] + get_motion_delta (decoder, \
motion->f_code[0]); \
motion_x = bound_motion_vector (motion_x, motion->f_code[0]); \
motion->pmv[1][0] = motion->pmv[0][0] = motion_x; \
NEEDBITS (bit_buf, bits, bit_ptr); \
other_x = ((motion_x + (motion_x > 0)) >> 1) + get_dmv (decoder); \
\
motion_y = motion->pmv[0][1] + get_motion_delta (decoder, \
motion->f_code[1]); \
motion_y = bound_motion_vector (motion_y, motion->f_code[1]); \
motion->pmv[1][1] = motion->pmv[0][1] = motion_y; \
other_y = (((motion_y + (motion_y > 0)) >> 1) + get_dmv (decoder) + \
decoder->dmv_offset); \
\
MOTION (mpeg2_mc.put, motion->ref[0], motion_x, motion_y, 16, 0); \
MOTION (mpeg2_mc.avg, motion->ref[1], other_x, other_y, 16, 0); \
} \
MOTION_FUNCTIONS (420, MOTION_420, MOTION_FIELD_420, MOTION_DMV_420,
MOTION_ZERO_420)
MOTION_FUNCTIONS (422, MOTION_422, MOTION_FIELD_422, MOTION_DMV_422,
MOTION_ZERO_422)
MOTION_FUNCTIONS (444, MOTION_444, MOTION_FIELD_444, MOTION_DMV_444,
MOTION_ZERO_444)
/* like motion_frame, but parsing without actual motion compensation */
static void motion_fr_conceal (mpeg2_decoder_t * const decoder)
{
int tmp;
NEEDBITS (bit_buf, bits, bit_ptr);
tmp = (decoder->f_motion.pmv[0][0] +
get_motion_delta (decoder, decoder->f_motion.f_code[0]));
tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[0]);
decoder->f_motion.pmv[1][0] = decoder->f_motion.pmv[0][0] = tmp;
NEEDBITS (bit_buf, bits, bit_ptr);
tmp = (decoder->f_motion.pmv[0][1] +
get_motion_delta (decoder, decoder->f_motion.f_code[1]));
tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[1]);
decoder->f_motion.pmv[1][1] = decoder->f_motion.pmv[0][1] = tmp;
DUMPBITS (bit_buf, bits, 1); /* remove marker_bit */
}
static void motion_fi_conceal (mpeg2_decoder_t * const decoder)
{
int tmp;
NEEDBITS (bit_buf, bits, bit_ptr);
DUMPBITS (bit_buf, bits, 1); /* remove field_select */
tmp = (decoder->f_motion.pmv[0][0] +
get_motion_delta (decoder, decoder->f_motion.f_code[0]));
tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[0]);
decoder->f_motion.pmv[1][0] = decoder->f_motion.pmv[0][0] = tmp;
NEEDBITS (bit_buf, bits, bit_ptr);
tmp = (decoder->f_motion.pmv[0][1] +
get_motion_delta (decoder, decoder->f_motion.f_code[1]));
tmp = bound_motion_vector (tmp, decoder->f_motion.f_code[1]);
decoder->f_motion.pmv[1][1] = decoder->f_motion.pmv[0][1] = tmp;
DUMPBITS (bit_buf, bits, 1); /* remove marker_bit */
}
#undef bit_buf
#undef bits
#undef bit_ptr
#define MOTION_CALL(routine,direction) \
do { \
if ((direction) & MACROBLOCK_MOTION_FORWARD) \
routine (decoder, &(decoder->f_motion), mpeg2_mc.put); \
if ((direction) & MACROBLOCK_MOTION_BACKWARD) \
routine (decoder, &(decoder->b_motion), \
((direction) & MACROBLOCK_MOTION_FORWARD ? \
mpeg2_mc.avg : mpeg2_mc.put)); \
} while (0)
#define NEXT_MACROBLOCK \
do { \
decoder->offset += 16; \
if (decoder->offset == decoder->width) { \
do { /* just so we can use the break statement */ \
if (decoder->convert) { \
decoder->convert (decoder->convert_id, decoder->dest, \
decoder->v_offset); \
if (decoder->coding_type == B_TYPE) \
break; \
} \
decoder->dest[0] += decoder->slice_stride; \
decoder->dest[1] += decoder->slice_uv_stride; \
decoder->dest[2] += decoder->slice_uv_stride; \
} while (0); \
decoder->v_offset += 16; \
if (decoder->v_offset > decoder->limit_y) { \
if (mpeg2_cpu_state_restore) \
mpeg2_cpu_state_restore (&cpu_state); \
return; \
} \
decoder->offset = 0; \
} \
} while (0)
void mpeg2_init_fbuf (mpeg2_decoder_t * decoder, uint8_t * current_fbuf[3],
uint8_t * forward_fbuf[3], uint8_t * backward_fbuf[3])
{
int offset, stride, height, bottom_field;
stride = decoder->stride_frame;
bottom_field = (decoder->picture_structure == BOTTOM_FIELD);
offset = bottom_field ? stride : 0;
height = decoder->height;
decoder->picture_dest[0] = current_fbuf[0] + offset;
decoder->picture_dest[1] = current_fbuf[1] + (offset >> 1);
decoder->picture_dest[2] = current_fbuf[2] + (offset >> 1);
decoder->f_motion.ref[0][0] = forward_fbuf[0] + offset;
decoder->f_motion.ref[0][1] = forward_fbuf[1] + (offset >> 1);
decoder->f_motion.ref[0][2] = forward_fbuf[2] + (offset >> 1);
decoder->b_motion.ref[0][0] = backward_fbuf[0] + offset;
decoder->b_motion.ref[0][1] = backward_fbuf[1] + (offset >> 1);
decoder->b_motion.ref[0][2] = backward_fbuf[2] + (offset >> 1);
if( decoder->picture_structure != FRAME_PICTURE )
{
decoder->dmv_offset = bottom_field ? 1 : -1;
decoder->f_motion.ref2[0] = decoder->f_motion.ref[bottom_field];
decoder->f_motion.ref2[1] = decoder->f_motion.ref[!bottom_field];
decoder->b_motion.ref2[0] = decoder->b_motion.ref[bottom_field];
decoder->b_motion.ref2[1] = decoder->b_motion.ref[!bottom_field];
offset = stride - offset;
if( decoder->second_field && (decoder->coding_type != B_TYPE) )
forward_fbuf = current_fbuf;
decoder->f_motion.ref[1][0] = forward_fbuf[0] + offset;
decoder->f_motion.ref[1][1] = forward_fbuf[1] + (offset >> 1);
decoder->f_motion.ref[1][2] = forward_fbuf[2] + (offset >> 1);
decoder->b_motion.ref[1][0] = backward_fbuf[0] + offset;
decoder->b_motion.ref[1][1] = backward_fbuf[1] + (offset >> 1);
decoder->b_motion.ref[1][2] = backward_fbuf[2] + (offset >> 1);
stride <<= 1;
height >>= 1;
}
decoder->stride = stride;
decoder->uv_stride = stride >> 1;
decoder->slice_stride = 16 * stride;
decoder->slice_uv_stride =
decoder->slice_stride >> (2 - decoder->chroma_format);
decoder->limit_x = 2 * decoder->width - 32;
decoder->limit_y_16 = 2 * height - 32;
decoder->limit_y_8 = 2 * height - 16;
decoder->limit_y = height - 16;
if( decoder->mpeg1 )
{
decoder->motion_parser[0] = motion_zero_420;
decoder->motion_parser[MC_FRAME] = motion_mp1;
decoder->motion_parser[4] = motion_reuse_420;
}
else if( decoder->picture_structure == FRAME_PICTURE )
{
if (decoder->chroma_format == 0)
{
decoder->motion_parser[0] = motion_zero_420;
decoder->motion_parser[MC_FIELD] = motion_fr_field_420;
decoder->motion_parser[MC_FRAME] = motion_fr_frame_420;
decoder->motion_parser[MC_DMV] = motion_fr_dmv_420;
decoder->motion_parser[4] = motion_reuse_420;
}
else if (decoder->chroma_format == 1)
{
decoder->motion_parser[0] = motion_zero_422;
decoder->motion_parser[MC_FIELD] = motion_fr_field_422;
decoder->motion_parser[MC_FRAME] = motion_fr_frame_422;
decoder->motion_parser[MC_DMV] = motion_fr_dmv_422;
decoder->motion_parser[4] = motion_reuse_422;
} else
{
decoder->motion_parser[0] = motion_zero_444;
decoder->motion_parser[MC_FIELD] = motion_fr_field_444;
decoder->motion_parser[MC_FRAME] = motion_fr_frame_444;
decoder->motion_parser[MC_DMV] = motion_fr_dmv_444;
decoder->motion_parser[4] = motion_reuse_444;
}
}
else
{
if (decoder->chroma_format == 0)
{
decoder->motion_parser[0] = motion_zero_420;
decoder->motion_parser[MC_FIELD] = motion_fi_field_420;
decoder->motion_parser[MC_16X8] = motion_fi_16x8_420;
decoder->motion_parser[MC_DMV] = motion_fi_dmv_420;
decoder->motion_parser[4] = motion_reuse_420;
}
else if (decoder->chroma_format == 1)
{
decoder->motion_parser[0] = motion_zero_422;
decoder->motion_parser[MC_FIELD] = motion_fi_field_422;
decoder->motion_parser[MC_16X8] = motion_fi_16x8_422;
decoder->motion_parser[MC_DMV] = motion_fi_dmv_422;
decoder->motion_parser[4] = motion_reuse_422;
}
else
{
decoder->motion_parser[0] = motion_zero_444;
decoder->motion_parser[MC_FIELD] = motion_fi_field_444;
decoder->motion_parser[MC_16X8] = motion_fi_16x8_444;
decoder->motion_parser[MC_DMV] = motion_fi_dmv_444;
decoder->motion_parser[4] = motion_reuse_444;
}
}
}
/* $Id:$
* Copyright (c) 2004 The Unichrome project. All rights reserved.
*
* This program 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, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTIES OR REPRESENTATIONS; 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.
*
*
*/
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/decoder.h>
#include "mpeg2.h"
#include "mpeg2_internal.h"
#include "xvmc_vld.h"
static uint8_t zig_zag_scan[64] ATTR_ALIGN(16) =
{
/* Zig-Zag scan pattern */
0, 1, 8,16, 9, 2, 3,10,
17,24,32,25,18,11, 4, 5,
12,19,26,33,40,48,41,34,
27,20,13, 6, 7,14,21,28,
35,42,49,56,57,50,43,36,
29,22,15,23,30,37,44,51,
58,59,52,45,38,31,39,46,
53,60,61,54,47,55,62,63
};
static uint8_t alternate_scan [64] ATTR_ALIGN(16) =
{
/* Alternate scan pattern */
0,8,16,24,1,9,2,10,17,25,32,40,48,56,57,49,
41,33,26,18,3,11,4,12,19,27,34,42,50,58,35,43,
51,59,20,28,5,13,6,14,21,29,36,44,52,60,37,45,
53,61,22,30,7,15,23,31,38,46,54,62,39,47,55,63
};
void mpeg2_xxmc_choose_coding(decoder_t *p_dec, mpeg2_decoder_t * const decoder, picture_t *picture,
double aspect_ratio, int flags)
{
if (picture)
{
//vlc_fourcc_t decoder_format = picture->format.i_chroma;
//if (decoder_format == VLC_FOURCC('X','x','M','C')) {
vlc_xxmc_t *xxmc = (vlc_xxmc_t *) picture->p_accel_data;
/*
* Make a request for acceleration type and mpeg coding from
* the output plugin.
*/
xxmc->fallback_format = VLC_FOURCC('Y','V','1','2');
xxmc->acceleration = VLC_XVMC_ACCEL_VLD;//| VLC_XVMC_ACCEL_IDCT| VLC_XVMC_ACCEL_MOCOMP ;
//msg_Dbg(p_dec, "mpeg2_xxmc_choose_coding 2");
/*
* Standard MOCOMP / IDCT XvMC implementation for interlaced streams
* is buggy. The bug is inherited from the old XvMC driver. Don't use it until
* it has been fixed. (A volunteer ?)
*/
//if ( decoder->picture_structure != 3 ) {
//xxmc->acceleration &= ~( VLC_XVMC_ACCEL_IDCT | VLC_XVMC_ACCEL_MOCOMP );
//}
xxmc->mpeg = (decoder->mpeg1) ? VLC_XVMC_MPEG_1:VLC_XVMC_MPEG_2;
xxmc->proc_xxmc_update_frame( picture,
decoder->width,
decoder->height,
aspect_ratio,
VLC_IMGFMT_XXMC, flags );
//}
}
}
void mpeg2_xxmc_slice( mpeg2dec_t *mpeg2dec, picture_t *picture, int code,
uint8_t *buffer, int size)
{
mpeg2_decoder_t * const decoder = &(mpeg2dec->decoder);
picture = (picture_t *)mpeg2dec->fbuf[0]->id;
vlc_xxmc_t *xxmc = (vlc_xxmc_t *) picture->p_accel_data;
vlc_vld_frame_t *vft = &xxmc->vld_frame;
unsigned mb_frame_height;
int i;
const uint8_t *scan_pattern;
if (1 == code)
{
//mpeg2_skip(mpeg2dec, 1);
//frame->bad_frame = 1;
/*
* Check that first field went through OK. Otherwise,
* indicate bad frame.
*/
if (decoder->second_field)
{
mpeg2dec->xvmc_last_slice_code = (xxmc->decoded) ? 0 : -1;
xxmc->decoded = 0;
}
else
{
mpeg2dec->xvmc_last_slice_code = 0;
}
mb_frame_height =
//(!(decoder->mpeg1) && (decoder->progressive_sequence)) ?
//2*((decoder->height+31) >> 5) :
(decoder->height+15) >> 4;
mpeg2dec->xxmc_mb_pic_height = (decoder->picture_structure == FRAME_PICTURE ) ?
mb_frame_height : mb_frame_height >> 1;
if (decoder->mpeg1)
{
vft->mv_ranges[0][0] = decoder->b_motion.f_code[0];
vft->mv_ranges[0][1] = decoder->b_motion.f_code[0];
vft->mv_ranges[1][0] = decoder->f_motion.f_code[0];
vft->mv_ranges[1][1] = decoder->f_motion.f_code[0];
}
else
{
vft->mv_ranges[0][0] = decoder->b_motion.f_code[0];
vft->mv_ranges[0][1] = decoder->b_motion.f_code[1];
vft->mv_ranges[1][0] = decoder->f_motion.f_code[0];
vft->mv_ranges[1][1] = decoder->f_motion.f_code[1];
}
vft->picture_structure = decoder->picture_structure;
vft->picture_coding_type = decoder->coding_type;
vft->mpeg_coding = (decoder->mpeg1) ? 0 : 1;
vft->progressive_sequence = decoder->progressive_sequence;
vft->scan = (decoder->scan == mpeg2_scan_alt);
vft->pred_dct_frame = decoder->frame_pred_frame_dct;
vft->concealment_motion_vectors =
decoder->concealment_motion_vectors;
vft->q_scale_type = decoder->q_scale_type;
vft->intra_vlc_format = decoder->intra_vlc_format;
vft->intra_dc_precision = 7 - decoder->intra_dc_precision;
vft->second_field = decoder->second_field;
/*
* Translation of libmpeg2's Q-matrix layout to VLD XvMC's.
* Errors here will give
* blocky artifacts and sometimes wrong colors.
*/
scan_pattern = (vft->scan) ? alternate_scan : zig_zag_scan;
if( (vft->load_intra_quantizer_matrix = decoder->load_intra_quantizer_matrix) )
{
for (i=0; i<64; ++i)
{
vft->intra_quantizer_matrix[scan_pattern[i]] =
mpeg2dec->quantizer_matrix[0][decoder->scan[i]];
}
}
if( (vft->load_non_intra_quantizer_matrix = decoder->load_non_intra_quantizer_matrix) )
{
for (i=0; i<64; ++i)
{
vft->non_intra_quantizer_matrix[scan_pattern[i]] =
mpeg2dec->quantizer_matrix[1][decoder->scan[i]];
}
}
decoder->load_intra_quantizer_matrix = 0;
decoder->load_non_intra_quantizer_matrix = 0;
vft->forward_reference_picture = (picture_t *)mpeg2dec->ptr_forward_ref_picture;
vft->backward_reference_picture = (picture_t *)mpeg2dec->ptr_backward_ref_picture;
#if 0
printf("\nSLICE DATA !!!! size=%d", size-4);
int i=0;
if ( vft->forward_reference_picture != NULL && ((vlc_xxmc_t *)
vft->forward_reference_picture->p_accel_data)->slice_data_size > 10)
{
printf("\nFORWARD SLICE DATA !!!! size=%d\n", ((vlc_xxmc_t *)
vft->forward_reference_picture->p_accel_data)->slice_data_size);
for (i=0;i<10;i++)
{
printf("%d ", *(((vlc_xxmc_t *) vft->forward_reference_picture->p_accel_data)->slice_data+i));
}
printf("\nFORWARD SLICE DATA END!!!!\n");
}
if ( vft->backward_reference_picture != NULL && ((vlc_xxmc_t *)
vft->backward_reference_picture->p_accel_data)->slice_data_size > 10)
{
printf("\nBACKWARD SLICE DATA !!!! size=%d\n", ((vlc_xxmc_t *)
vft->backward_reference_picture->p_accel_data)->slice_data_size);
for (i=0;i<10;i++)
{
printf("%d ", *(((vlc_xxmc_t *) vft->backward_reference_picture->p_accel_data)->slice_data+i));
}
printf("\nBACKWARD SLICE DATA END!!!!\n");
}
#endif
xxmc->proc_xxmc_begin( picture );
if (xxmc->result != 0)
{
/* "mpeg2_xxmc_slice begin failed" */
/* xmc->proc_xxmc_flushsync( picture ); */
xxmc->proc_xxmc_flush( picture );
mpeg2dec->xvmc_last_slice_code=-1;
}
}
if( ((code == mpeg2dec->xvmc_last_slice_code + 1 ||
code == mpeg2dec->xvmc_last_slice_code)) &&
code <= mpeg2dec->xxmc_mb_pic_height )
{
/*
* Send this slice to the output plugin. May stall for a long
* time in proc_slice;
*/
//mpeg2_skip(mpeg2dec, 1);
//frame->bad_frame = 1;
//size = mpeg2dec->chunk_ptr-mpeg2dec->chunk_start;
xxmc->slice_data_size = size;//mpeg2dec->buf_end - mpeg2dec->buf_start;
xxmc->slice_data = mpeg2dec->chunk_start;//buffer;
xxmc->slice_code = code;
xxmc->proc_xxmc_slice( picture );
if (xxmc->result != 0)
{
//xxmc->proc_xxmc_flushsync( picture );
xxmc->proc_xxmc_flush( picture );
mpeg2dec->xvmc_last_slice_code=-1;
return;
}
if (code == mpeg2dec->xxmc_mb_pic_height)
{
/*
* We've encountered the last slice of this frame.
* Release the decoder for a new frame and, if all
* went well, tell libmpeg2 that we are ready.
*/
mpeg2_xxmc_vld_frame_complete(mpeg2dec,picture,code);
return;
}
else if (code == mpeg2dec->xvmc_last_slice_code + 1)
{
//xxmc->proc_xxmc_flush( picture );
/*
* Keep track of slices.
*/
mpeg2dec->xvmc_last_slice_code++;
}
}
else
{
/*
* An error has occured.
*/
//printf("VLD XvMC: Slice error: code=%d\tlast slice code=%d\tmb_pic_height=%d\n", code, mpeg2dec->xvmc_last_slice_code,mpeg2dec->xxmc_mb_pic_height);
mpeg2dec->xvmc_last_slice_code = -1;
xxmc->proc_xxmc_flush( picture );
return;
}
}
void mpeg2_xxmc_vld_frame_complete(mpeg2dec_t *mpeg2dec, picture_t *picture, int code)
{
vlc_xxmc_t *xxmc = (vlc_xxmc_t *) picture->p_accel_data;
vlc_vld_frame_t *vft = &xxmc->vld_frame;
if (xxmc->decoded)
return;
if (mpeg2dec->xvmc_last_slice_code >= 1)
{
xxmc->proc_xxmc_flush( picture );
if (xxmc->result)
{
mpeg2dec->xvmc_last_slice_code=-1;
return;
}
xxmc->decoded = 1;
mpeg2dec->xvmc_last_slice_code++;
if (vft->picture_structure == 3 || vft->second_field)
{
if (xxmc->result == 0)
mpeg2_skip(mpeg2dec, 0);
//frame->bad_frame = 0;
}
}
}
/* $Id:$
* vlc.h
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec 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.
*
* mpeg2dec 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
*/
#define GETWORD(bit_buf,shift,bit_ptr) \
do { \
bit_buf |= ((bit_ptr[0] << 8) | bit_ptr[1]) << (shift); \
bit_ptr += 2; \
} while (0)
static inline void bitstream_init (mpeg2_decoder_t * decoder,
const uint8_t * start)
{
decoder->bitstream_buf =
(start[0] << 24) | (start[1] << 16) | (start[2] << 8) | start[3];
decoder->bitstream_ptr = start + 4;
decoder->bitstream_bits = -16;
}
/* make sure that there are at least 16 valid bits in bit_buf */
#define NEEDBITS(bit_buf,bits,bit_ptr) \
do { \
if (unlikely (bits > 0)) { \
GETWORD (bit_buf, bits, bit_ptr); \
bits -= 16; \
} \
} while (0)
/* remove num valid bits from bit_buf */
#define DUMPBITS(bit_buf,bits,num) \
do { \
bit_buf <<= (num); \
bits += (num); \
} while (0)
/* take num bits from the high part of bit_buf and zero extend them */
#define UBITS(bit_buf,num) (((uint32_t)(bit_buf)) >> (32 - (num)))
/* take num bits from the high part of bit_buf and sign extend them */
#define SBITS(bit_buf,num) (((int32_t)(bit_buf)) >> (32 - (num)))
typedef struct
{
uint8_t modes;
uint8_t len;
} MBtab;
typedef struct
{
uint8_t delta;
uint8_t len;
} MVtab;
typedef struct
{
int8_t dmv;
uint8_t len;
} DMVtab;
typedef struct
{
uint8_t cbp;
uint8_t len;
} CBPtab;
typedef struct
{
uint8_t size;
uint8_t len;
} DCtab;
typedef struct
{
uint8_t run;
uint8_t level;
uint8_t len;
} DCTtab;
typedef struct
{
uint8_t mba;
uint8_t len;
} MBAtab;
#define INTRA MACROBLOCK_INTRA
#define QUANT MACROBLOCK_QUANT
static const MBtab MB_I [] =
{
{INTRA|QUANT, 2}, {INTRA, 1}
};
#define MC MACROBLOCK_MOTION_FORWARD
#define CODED MACROBLOCK_PATTERN
static const MBtab MB_P [] =
{
{INTRA|QUANT, 6}, {CODED|QUANT, 5}, {MC|CODED|QUANT, 5}, {INTRA, 5},
{MC, 3}, {MC, 3}, {MC, 3}, {MC, 3},
{CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2},
{CODED, 2}, {CODED, 2}, {CODED, 2}, {CODED, 2},
{MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1},
{MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1},
{MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1},
{MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}, {MC|CODED, 1}
};
#define FWD MACROBLOCK_MOTION_FORWARD
#define BWD MACROBLOCK_MOTION_BACKWARD
#define INTER MACROBLOCK_MOTION_FORWARD|MACROBLOCK_MOTION_BACKWARD
static const MBtab MB_B [] =
{
{0, 0}, {INTRA|QUANT, 6},
{BWD|CODED|QUANT, 6}, {FWD|CODED|QUANT, 6},
{INTER|CODED|QUANT, 5}, {INTER|CODED|QUANT, 5},
{INTRA, 5}, {INTRA, 5},
{FWD, 4}, {FWD, 4}, {FWD, 4}, {FWD, 4},
{FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4}, {FWD|CODED, 4},
{BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3},
{BWD, 3}, {BWD, 3}, {BWD, 3}, {BWD, 3},
{BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3},
{BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3}, {BWD|CODED, 3},
{INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2},
{INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2},
{INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2},
{INTER, 2}, {INTER, 2}, {INTER, 2}, {INTER, 2},
{INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2},
{INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2},
{INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2},
{INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}, {INTER|CODED, 2}
};
#undef INTRA
#undef QUANT
#undef MC
#undef CODED
#undef FWD
#undef BWD
#undef INTER
static const MVtab MV_4 [] =
{
{ 3, 6}, { 2, 4}, { 1, 3}, { 1, 3}, { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2}
};
static const MVtab MV_10 [] =
{
{ 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10}, { 0,10},
{ 0,10}, { 0,10}, { 0,10}, { 0,10}, {15,10}, {14,10}, {13,10}, {12,10},
{11,10}, {10,10}, { 9, 9}, { 9, 9}, { 8, 9}, { 8, 9}, { 7, 9}, { 7, 9},
{ 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7}, { 6, 7},
{ 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7}, { 5, 7},
{ 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}, { 4, 7}
};
static const DMVtab DMV_2 [] =
{
{ 0, 1}, { 0, 1}, { 1, 2}, {-1, 2}
};
static const CBPtab CBP_7 [] =
{
{0x11, 7}, {0x12, 7}, {0x14, 7}, {0x18, 7},
{0x21, 7}, {0x22, 7}, {0x24, 7}, {0x28, 7},
{0x3f, 6}, {0x3f, 6}, {0x30, 6}, {0x30, 6},
{0x09, 6}, {0x09, 6}, {0x06, 6}, {0x06, 6},
{0x1f, 5}, {0x1f, 5}, {0x1f, 5}, {0x1f, 5},
{0x10, 5}, {0x10, 5}, {0x10, 5}, {0x10, 5},
{0x2f, 5}, {0x2f, 5}, {0x2f, 5}, {0x2f, 5},
{0x20, 5}, {0x20, 5}, {0x20, 5}, {0x20, 5},
{0x07, 5}, {0x07, 5}, {0x07, 5}, {0x07, 5},
{0x0b, 5}, {0x0b, 5}, {0x0b, 5}, {0x0b, 5},
{0x0d, 5}, {0x0d, 5}, {0x0d, 5}, {0x0d, 5},
{0x0e, 5}, {0x0e, 5}, {0x0e, 5}, {0x0e, 5},
{0x05, 5}, {0x05, 5}, {0x05, 5}, {0x05, 5},
{0x0a, 5}, {0x0a, 5}, {0x0a, 5}, {0x0a, 5},
{0x03, 5}, {0x03, 5}, {0x03, 5}, {0x03, 5},
{0x0c, 5}, {0x0c, 5}, {0x0c, 5}, {0x0c, 5},
{0x01, 4}, {0x01, 4}, {0x01, 4}, {0x01, 4},
{0x01, 4}, {0x01, 4}, {0x01, 4}, {0x01, 4},
{0x02, 4}, {0x02, 4}, {0x02, 4}, {0x02, 4},
{0x02, 4}, {0x02, 4}, {0x02, 4}, {0x02, 4},
{0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4},
{0x04, 4}, {0x04, 4}, {0x04, 4}, {0x04, 4},
{0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4},
{0x08, 4}, {0x08, 4}, {0x08, 4}, {0x08, 4},
{0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3},
{0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3},
{0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3},
{0x0f, 3}, {0x0f, 3}, {0x0f, 3}, {0x0f, 3}
};
static const CBPtab CBP_9 [] =
{
{0, 0}, {0x00, 9}, {0x39, 9}, {0x36, 9},
{0x37, 9}, {0x3b, 9}, {0x3d, 9}, {0x3e, 9},
{0x17, 8}, {0x17, 8}, {0x1b, 8}, {0x1b, 8},
{0x1d, 8}, {0x1d, 8}, {0x1e, 8}, {0x1e, 8},
{0x27, 8}, {0x27, 8}, {0x2b, 8}, {0x2b, 8},
{0x2d, 8}, {0x2d, 8}, {0x2e, 8}, {0x2e, 8},
{0x19, 8}, {0x19, 8}, {0x16, 8}, {0x16, 8},
{0x29, 8}, {0x29, 8}, {0x26, 8}, {0x26, 8},
{0x35, 8}, {0x35, 8}, {0x3a, 8}, {0x3a, 8},
{0x33, 8}, {0x33, 8}, {0x3c, 8}, {0x3c, 8},
{0x15, 8}, {0x15, 8}, {0x1a, 8}, {0x1a, 8},
{0x13, 8}, {0x13, 8}, {0x1c, 8}, {0x1c, 8},
{0x25, 8}, {0x25, 8}, {0x2a, 8}, {0x2a, 8},
{0x23, 8}, {0x23, 8}, {0x2c, 8}, {0x2c, 8},
{0x31, 8}, {0x31, 8}, {0x32, 8}, {0x32, 8},
{0x34, 8}, {0x34, 8}, {0x38, 8}, {0x38, 8}
};
static const DCtab DC_lum_5 [] =
{
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2},
{0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3},
{4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5}
};
static const DCtab DC_chrom_5 [] =
{
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2},
{3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5}
};
static const DCtab DC_long [] =
{
{6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5},
{6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, {6, 5}, { 6, 5}, { 6, 5},
{7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, { 7, 6}, { 7, 6},
{8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9}
};
static const DCTtab DCT_16 [] =
{
{129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0},
{129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0},
{129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0},
{129, 0, 0}, {129, 0, 0}, {129, 0, 0}, {129, 0, 0},
{ 2,18, 0}, { 2,17, 0}, { 2,16, 0}, { 2,15, 0},
{ 7, 3, 0}, { 17, 2, 0}, { 16, 2, 0}, { 15, 2, 0},
{ 14, 2, 0}, { 13, 2, 0}, { 12, 2, 0}, { 32, 1, 0},
{ 31, 1, 0}, { 30, 1, 0}, { 29, 1, 0}, { 28, 1, 0}
};
static const DCTtab DCT_15 [] =
{
{ 1,40,15}, { 1,39,15}, { 1,38,15}, { 1,37,15},
{ 1,36,15}, { 1,35,15}, { 1,34,15}, { 1,33,15},
{ 1,32,15}, { 2,14,15}, { 2,13,15}, { 2,12,15},
{ 2,11,15}, { 2,10,15}, { 2, 9,15}, { 2, 8,15},
{ 1,31,14}, { 1,31,14}, { 1,30,14}, { 1,30,14},
{ 1,29,14}, { 1,29,14}, { 1,28,14}, { 1,28,14},
{ 1,27,14}, { 1,27,14}, { 1,26,14}, { 1,26,14},
{ 1,25,14}, { 1,25,14}, { 1,24,14}, { 1,24,14},
{ 1,23,14}, { 1,23,14}, { 1,22,14}, { 1,22,14},
{ 1,21,14}, { 1,21,14}, { 1,20,14}, { 1,20,14},
{ 1,19,14}, { 1,19,14}, { 1,18,14}, { 1,18,14},
{ 1,17,14}, { 1,17,14}, { 1,16,14}, { 1,16,14}
};
static const DCTtab DCT_13 [] =
{
{ 11, 2,13}, { 10, 2,13}, { 6, 3,13}, { 4, 4,13},
{ 3, 5,13}, { 2, 7,13}, { 2, 6,13}, { 1,15,13},
{ 1,14,13}, { 1,13,13}, { 1,12,13}, { 27, 1,13},
{ 26, 1,13}, { 25, 1,13}, { 24, 1,13}, { 23, 1,13},
{ 1,11,12}, { 1,11,12}, { 9, 2,12}, { 9, 2,12},
{ 5, 3,12}, { 5, 3,12}, { 1,10,12}, { 1,10,12},
{ 3, 4,12}, { 3, 4,12}, { 8, 2,12}, { 8, 2,12},
{ 22, 1,12}, { 22, 1,12}, { 21, 1,12}, { 21, 1,12},
{ 1, 9,12}, { 1, 9,12}, { 20, 1,12}, { 20, 1,12},
{ 19, 1,12}, { 19, 1,12}, { 2, 5,12}, { 2, 5,12},
{ 4, 3,12}, { 4, 3,12}, { 1, 8,12}, { 1, 8,12},
{ 7, 2,12}, { 7, 2,12}, { 18, 1,12}, { 18, 1,12}
};
static const DCTtab DCT_B14_10 [] =
{
{ 17, 1,10}, { 6, 2,10}, { 1, 7,10}, { 3, 3,10},
{ 2, 4,10}, { 16, 1,10}, { 15, 1,10}, { 5, 2,10}
};
static const DCTtab DCT_B14_8 [] =
{
{ 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6},
{ 3, 2, 7}, { 3, 2, 7}, { 10, 1, 7}, { 10, 1, 7},
{ 1, 4, 7}, { 1, 4, 7}, { 9, 1, 7}, { 9, 1, 7},
{ 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6}, { 8, 1, 6},
{ 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6}, { 7, 1, 6},
{ 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6}, { 2, 2, 6},
{ 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6},
{ 14, 1, 8}, { 1, 6, 8}, { 13, 1, 8}, { 12, 1, 8},
{ 4, 2, 8}, { 2, 3, 8}, { 1, 5, 8}, { 11, 1, 8}
};
static const DCTtab DCT_B14AC_5 [] =
{
{ 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5},
{ 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2},
{129, 0, 2}, {129, 0, 2}, {129, 0, 2}, {129, 0, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}
};
static const DCTtab DCT_B14DC_5 [] =
{
{ 1, 3, 5}, { 5, 1, 5}, { 4, 1, 5},
{ 1, 2, 4}, { 1, 2, 4}, { 3, 1, 4}, { 3, 1, 4},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{ 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1},
{ 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1},
{ 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1},
{ 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}, { 1, 1, 1}
};
static const DCTtab DCT_B15_10 [] =
{
{ 6, 2, 9}, { 6, 2, 9}, { 15, 1, 9}, { 15, 1, 9},
{ 3, 4,10}, { 17, 1,10}, { 16, 1, 9}, { 16, 1, 9}
};
static const DCTtab DCT_B15_8 [] =
{
{ 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6}, { 65, 0, 6},
{ 8, 1, 7}, { 8, 1, 7}, { 9, 1, 7}, { 9, 1, 7},
{ 7, 1, 7}, { 7, 1, 7}, { 3, 2, 7}, { 3, 2, 7},
{ 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6}, { 1, 7, 6},
{ 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6}, { 1, 6, 6},
{ 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6}, { 5, 1, 6},
{ 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6}, { 6, 1, 6},
{ 2, 5, 8}, { 12, 1, 8}, { 1,11, 8}, { 1,10, 8},
{ 14, 1, 8}, { 13, 1, 8}, { 4, 2, 8}, { 2, 4, 8},
{ 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5},
{ 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5}, { 3, 1, 5},
{ 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5},
{ 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5}, { 2, 2, 5},
{ 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5},
{ 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5}, { 4, 1, 5},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{ 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3}, { 2, 1, 3},
{129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4},
{129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4},
{129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4},
{129, 0, 4}, {129, 0, 4}, {129, 0, 4}, {129, 0, 4},
{ 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4},
{ 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4},
{ 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4},
{ 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4}, { 1, 3, 4},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2}, { 1, 1, 2},
{ 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3},
{ 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3},
{ 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3},
{ 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3},
{ 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3},
{ 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3},
{ 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3},
{ 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3}, { 1, 2, 3},
{ 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5},
{ 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5}, { 1, 4, 5},
{ 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5},
{ 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5}, { 1, 5, 5},
{ 10, 1, 7}, { 10, 1, 7}, { 2, 3, 7}, { 2, 3, 7},
{ 11, 1, 7}, { 11, 1, 7}, { 1, 8, 7}, { 1, 8, 7},
{ 1, 9, 7}, { 1, 9, 7}, { 1,12, 8}, { 1,13, 8},
{ 3, 3, 8}, { 5, 2, 8}, { 1,14, 8}, { 1,15, 8}
};
static const MBAtab MBA_5 [] =
{
{6, 5}, {5, 5}, {4, 4}, {4, 4}, {3, 4}, {3, 4},
{2, 3}, {2, 3}, {2, 3}, {2, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}
};
static const MBAtab MBA_11 [] =
{
{32, 11}, {31, 11}, {30, 11}, {29, 11},
{28, 11}, {27, 11}, {26, 11}, {25, 11},
{24, 11}, {23, 11}, {22, 11}, {21, 11},
{20, 10}, {20, 10}, {19, 10}, {19, 10},
{18, 10}, {18, 10}, {17, 10}, {17, 10},
{16, 10}, {16, 10}, {15, 10}, {15, 10},
{14, 8}, {14, 8}, {14, 8}, {14, 8},
{14, 8}, {14, 8}, {14, 8}, {14, 8},
{13, 8}, {13, 8}, {13, 8}, {13, 8},
{13, 8}, {13, 8}, {13, 8}, {13, 8},
{12, 8}, {12, 8}, {12, 8}, {12, 8},
{12, 8}, {12, 8}, {12, 8}, {12, 8},
{11, 8}, {11, 8}, {11, 8}, {11, 8},
{11, 8}, {11, 8}, {11, 8}, {11, 8},
{10, 8}, {10, 8}, {10, 8}, {10, 8},
{10, 8}, {10, 8}, {10, 8}, {10, 8},
{ 9, 8}, { 9, 8}, { 9, 8}, { 9, 8},
{ 9, 8}, { 9, 8}, { 9, 8}, { 9, 8},
{ 8, 7}, { 8, 7}, { 8, 7}, { 8, 7},
{ 8, 7}, { 8, 7}, { 8, 7}, { 8, 7},
{ 8, 7}, { 8, 7}, { 8, 7}, { 8, 7},
{ 8, 7}, { 8, 7}, { 8, 7}, { 8, 7},
{ 7, 7}, { 7, 7}, { 7, 7}, { 7, 7},
{ 7, 7}, { 7, 7}, { 7, 7}, { 7, 7},
{ 7, 7}, { 7, 7}, { 7, 7}, { 7, 7},
{ 7, 7}, { 7, 7}, { 7, 7}, { 7, 7}
};
/* $Id:$
* Copyright (c) 2004 The Unichrome project. All rights reserved.
*
* This program 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, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTIES OR REPRESENTATIONS; 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.
*
*
*/
#ifndef _XVMC_VLD_H
#define _XVMC_VLD_H
#include "accel_xvmc.h"
//#include "xvmc.h"
extern void mpeg2_xxmc_slice( mpeg2dec_t *mpeg2dec, picture_t *picture,
int code, uint8_t *buffer, int size );
extern void mpeg2_xxmc_choose_coding( decoder_t *p_dec,
mpeg2_decoder_t * const decoder, picture_t *picture,
double aspect_ratio, int flags );
extern void mpeg2_xxmc_vld_frame_complete( mpeg2dec_t *mpeg2dec,
picture_t *picture, int code );
#endif
/* include/config.h. Generated by configure. */
/* include/config.h.in. Generated from configure.in by autoheader. */
/* autodetect accelerations */
#define ACCEL_DETECT
/* alpha architecture */
/* #undef ARCH_ALPHA */
/* ppc architecture */
/* #undef ARCH_PPC */
/* sparc architecture */
/* #undef ARCH_SPARC */
/* x86 architecture */
#define ARCH_X86
/* maximum supported data alignment */
#define ATTRIBUTE_ALIGNED_MAX 64
/* debug mode configuration */
/* #undef DEBUG */
/* Define to 1 if you have the <altivec.h> header file. */
/* #undef HAVE_ALTIVEC_H */
/* Define if you have the `__builtin_expect' function. */
#define HAVE_BUILTIN_EXPECT
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the `ftime' function. */
#define HAVE_FTIME 1
/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <io.h> header file. */
/* #undef HAVE_IO_H */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if the system has the type `struct timeval'. */
#define HAVE_STRUCT_TIMEVAL 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/timeb.h> header file. */
#define HAVE_SYS_TIMEB_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <time.h> header file. */
#define HAVE_TIME_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* libvo DirectX support */
/* #undef LIBVO_DX */
/* libvo SDL support */
/* #undef LIBVO_SDL */
/* libvo X11 support */
#define LIBVO_X11
/* libvo Xv support */
#define LIBVO_XV
/* mpeg2dec profiling */
/* #undef MPEG2DEC_GPROF */
/* Name of package */
#define PACKAGE "mpeg2dec"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* The size of a `char', as computed by sizeof. */
/* #undef SIZEOF_CHAR */
/* The size of a `int', as computed by sizeof. */
/* #undef SIZEOF_INT */
/* The size of a `long', as computed by sizeof. */
/* #undef SIZEOF_LONG */
/* The size of a `short', as computed by sizeof. */
/* #undef SIZEOF_SHORT */
/* The size of a `void*', as computed by sizeof. */
/* #undef SIZEOF_VOIDP */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* Version number of package */
#define VERSION "0.4.0"
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
/* #undef WORDS_BIGENDIAN */
/* Define to 1 if the X Window System is missing or not being used. */
/* #undef X_DISPLAY_MISSING */
/* Number of bits in a file offset, on hosts where this is settable. */
#define _FILE_OFFSET_BITS 64
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#define inline __attribute__ ((__always_inline__))
#endif
/* Define as `__restrict' if that's what the C compiler calls it, or to
nothing if it is not supported. */
#define restrict __restrict__
/* Define to `unsigned' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define to empty if the keyword `volatile' does not work. Warning: valid
code using `volatile' can become incorrect without. Disable with care. */
/* #undef volatile */
/*****************************************************************************
* xxmc.c : HW MPEG decoder thread
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id$
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Laurent Aimar <fenrir@via.ecp.fr>
*
* This program 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.
*
* This program 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, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/vout.h>
#include <vlc/decoder.h>
#include <mcheck.h>
#include "mpeg2.h"
#include "attributes.h"
#include "mpeg2_internal.h"
#include "xvmc_vld.h"
#include "vout_synchro.h"
/* Aspect ratio (ISO/IEC 13818-2 section 6.3.3, table 6-3) */
#define AR_SQUARE_PICTURE 1 /* square pixels */
#define AR_3_4_PICTURE 2 /* 3:4 picture (TV) */
#define AR_16_9_PICTURE 3 /* 16:9 picture (wide screen) */
#define AR_221_1_PICTURE 4 /* 2.21:1 picture (movie) */
#include <unistd.h>
/*****************************************************************************
* decoder_sys_t : libmpeg2 decoder descriptor
*****************************************************************************/
struct decoder_sys_t
{
/*
* libmpeg2 properties
*/
mpeg2dec_t *p_mpeg2dec;
const mpeg2_info_t *p_info;
vlc_bool_t b_skip;
/*
* Input properties
*/
pes_packet_t *p_pes; /* current PES we are decoding */
mtime_t i_pts;
mtime_t i_previous_pts;
mtime_t i_current_pts;
mtime_t i_previous_dts;
mtime_t i_current_dts;
int i_current_rate;
picture_t * p_picture_to_destroy;
vlc_bool_t b_garbage_pic;
vlc_bool_t b_after_sequence_header; /* is it the next frame after
* the sequence header ? */
vlc_bool_t b_slice_i; /* intra-slice refresh stream */
/*
* Output properties
*/
vout_synchro_t *p_synchro;
int i_aspect;
mtime_t i_last_frame_pts;
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int OpenDecoder( vlc_object_t * );
static void CloseDecoder( vlc_object_t * );
static picture_t *DecodeBlock( decoder_t *, block_t ** );
static picture_t *GetNewPicture( decoder_t *, uint8_t ** );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("MPEG I/II hw video decoder (using libmpeg2)") );
set_capability( "decoder", 160 );
set_callbacks( OpenDecoder, CloseDecoder );
add_shortcut( "xxmc" );
vlc_module_end();
/*****************************************************************************
* OpenDecoder: probe the decoder and return score
*****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
decoder_t *p_dec = (decoder_t*)p_this;
decoder_sys_t *p_sys;
uint32_t i_accel = 0;
FILE *f_wd_dec;
msg_Dbg(p_dec, "OpenDecoder Entering");
mtrace();
if( p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','g','v') &&
p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','g','1') &&
/* Pinnacle hardware-mpeg1 */
p_dec->fmt_in.i_codec != VLC_FOURCC('P','I','M','1') &&
/* VIA hardware-mpeg2 */
p_dec->fmt_in.i_codec != VLC_FOURCC('X','x','M','C') &&
/* ATI Video */
p_dec->fmt_in.i_codec != VLC_FOURCC('V','C','R','2') &&
p_dec->fmt_in.i_codec != VLC_FOURCC('m','p','g','2') )
{
return VLC_EGENERIC;
}
/* Allocate the memory needed to store the decoder's structure */
if( ( p_dec->p_sys = p_sys =
(decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
{
msg_Err( p_dec, "out of memory" );
return VLC_EGENERIC;
}
/* Initialize the thread properties */
memset( p_sys, 0, sizeof(decoder_sys_t) );
p_sys->p_pes = NULL;
p_sys->p_mpeg2dec = NULL;
p_sys->p_synchro = NULL;
p_sys->p_info = NULL;
p_sys->i_pts = mdate() + DEFAULT_PTS_DELAY;
p_sys->i_current_pts = 0;
p_sys->i_previous_pts = 0;
p_sys->i_current_dts = 0;
p_sys->i_previous_dts = 0;
p_sys->p_picture_to_destroy = NULL;
p_sys->b_garbage_pic = 0;
p_sys->b_slice_i = 0;
p_sys->b_skip = 0;
#if defined( __i386__ )
if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_MMX )
{
i_accel |= MPEG2_ACCEL_X86_MMX;
}
if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_3DNOW )
{
i_accel |= MPEG2_ACCEL_X86_3DNOW;
}
if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT )
{
i_accel |= MPEG2_ACCEL_X86_MMXEXT;
}
#elif defined( __powerpc__ ) || defined( SYS_DARWIN )
if( p_dec->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC )
{
i_accel |= MPEG2_ACCEL_PPC_ALTIVEC;
}
#else
/* If we do not know this CPU, trust libmpeg2's feature detection */
i_accel = MPEG2_ACCEL_DETECT;
#endif
/* Set CPU acceleration features */
mpeg2_accel( i_accel );
/* Initialize decoder */
p_sys->p_mpeg2dec = mpeg2_init();
if( p_sys->p_mpeg2dec == NULL)
{
msg_Err( p_dec, "mpeg2_init() failed" );
free( p_sys );
return VLC_EGENERIC;
}
p_sys->p_info = mpeg2_info( p_sys->p_mpeg2dec );
p_dec->pf_decode_video = DecodeBlock;
f_wd_dec = fopen("/vlc/dec_pid", "w");
if (f_wd_dec != NULL)
{
fprintf(f_wd_dec, "%d\n", getpid());
fflush(f_wd_dec);
fclose(f_wd_dec);
}
msg_Dbg(p_dec, "OpenDecoder Leaving");
return VLC_SUCCESS;
}
static void WriteDecodeFile(int value)
{
FILE *f_wd_ok;
f_wd_ok = fopen("/vlc/dec_ok", "w");
if (f_wd_ok != NULL)
{
fprintf(f_wd_ok, "%d", value);
fflush(f_wd_ok);
fclose(f_wd_ok);
}
}
/*****************************************************************************
* RunDecoder: the libmpeg2 decoder
*****************************************************************************/
static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
{
decoder_sys_t *p_sys = p_dec->p_sys;
mpeg2_state_t state;
picture_t *p_pic;
block_t *p_block;
if( !pp_block || !*pp_block )
return NULL;
p_block = *pp_block;
while( 1 )
{
state = mpeg2_parse( p_sys->p_mpeg2dec );
switch( state )
{
case STATE_BUFFER:
if( !p_block->i_buffer )
{
block_Release( p_block );
return NULL;
}
if( (p_block->i_flags&BLOCK_FLAG_DISCONTINUITY) &&
p_sys->p_synchro &&
p_sys->p_info->sequence &&
p_sys->p_info->sequence->width != (unsigned int)-1 )
{
vout_SynchroReset( p_sys->p_synchro );
if( p_sys->p_info->current_fbuf != NULL
&& p_sys->p_info->current_fbuf->id != NULL )
{
p_sys->b_garbage_pic = 1;
p_pic = p_sys->p_info->current_fbuf->id;
}
else
{
uint8_t *buf[3];
buf[0] = buf[1] = buf[2] = NULL;
if( (p_pic = GetNewPicture( p_dec, buf )) == NULL )
break;
mpeg2_set_buf( p_sys->p_mpeg2dec, buf, p_pic );
}
p_sys->p_picture_to_destroy = p_pic;
if ( p_sys->b_slice_i )
{
vout_SynchroNewPicture( p_sys->p_synchro,
I_CODING_TYPE, 2, 0, 0, p_sys->i_current_rate );
vout_SynchroDecode( p_sys->p_synchro );
vout_SynchroEnd( p_sys->p_synchro, I_CODING_TYPE, 0 );
}
}
#ifdef PIC_FLAG_PTS
if( p_block->i_pts )
{
mpeg2_pts( p_sys->p_mpeg2dec, (uint32_t)p_block->i_pts );
#else /* New interface */
if( p_block->i_pts || p_block->i_dts )
{
mpeg2_tag_picture( p_sys->p_mpeg2dec,
(uint32_t)p_block->i_pts,
(uint32_t)p_block->i_dts );
#endif
p_sys->i_previous_pts = p_sys->i_current_pts;
p_sys->i_current_pts = p_block->i_pts;
p_sys->i_previous_dts = p_sys->i_current_dts;
p_sys->i_current_dts = p_block->i_dts;
}
p_sys->i_current_rate = p_block->i_rate;
mpeg2_buffer( p_sys->p_mpeg2dec, p_block->p_buffer,
p_block->p_buffer + p_block->i_buffer );
p_block->i_buffer = 0;
break;
case STATE_SEQUENCE:
{
/* Initialize video output */
uint8_t *buf[3];
buf[0] = buf[1] = buf[2] = NULL;
/* Check whether the input gave a particular aspect ratio */
if( p_dec->fmt_in.video.i_aspect )
{
p_sys->i_aspect = p_dec->fmt_in.video.i_aspect;
if( p_sys->i_aspect <= AR_221_1_PICTURE )
switch( p_sys->i_aspect )
{
case AR_3_4_PICTURE:
p_sys->i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;
break;
case AR_16_9_PICTURE:
p_sys->i_aspect = VOUT_ASPECT_FACTOR * 16 / 9;
break;
case AR_221_1_PICTURE:
p_sys->i_aspect = VOUT_ASPECT_FACTOR * 221 / 100;
break;
case AR_SQUARE_PICTURE:
p_sys->i_aspect = VOUT_ASPECT_FACTOR *
p_sys->p_info->sequence->width /
p_sys->p_info->sequence->height;
break;
}
}
else
{
/* Use the value provided in the MPEG sequence header */
if( p_sys->p_info->sequence->pixel_height > 0 )
{
p_sys->i_aspect =
((uint64_t)p_sys->p_info->sequence->display_width) *
p_sys->p_info->sequence->pixel_width *
VOUT_ASPECT_FACTOR /
p_sys->p_info->sequence->display_height /
p_sys->p_info->sequence->pixel_height;
}
else
{
/* Invalid aspect, assume 4:3.
* This shouldn't happen and if it does it is a bug
* in libmpeg2 (likely triggered by an invalid stream) */
p_sys->i_aspect = VOUT_ASPECT_FACTOR * 4 / 3;
}
}
msg_Dbg( p_dec, "%dx%d, aspect %d, %u.%03u fps",
p_sys->p_info->sequence->width,
p_sys->p_info->sequence->height, p_sys->i_aspect,
(uint32_t)((uint64_t)1001000000 * 27 /
p_sys->p_info->sequence->frame_period / 1001),
(uint32_t)((uint64_t)1001000000 * 27 /
p_sys->p_info->sequence->frame_period % 1001) );
mpeg2_custom_fbuf( p_sys->p_mpeg2dec, 1 );
/* Set the first 2 reference frames */
mpeg2_set_buf( p_sys->p_mpeg2dec, buf, NULL );
if( (p_pic = GetNewPicture( p_dec, buf )) == NULL )
{
block_Release( p_block );
return NULL;
}
mpeg2_set_buf( p_sys->p_mpeg2dec, buf, p_pic );
p_pic->date = 0;
p_dec->pf_picture_link( p_dec, p_pic );
if( p_sys->p_synchro )
{
vout_SynchroRelease( p_sys->p_synchro );
}
p_sys->p_synchro = vout_SynchroInit( p_dec,
(uint32_t)((uint64_t)1001000000 * 27 /
p_sys->p_info->sequence->frame_period) );
p_sys->b_after_sequence_header = 1;
}
break;
case STATE_PICTURE_2ND:
vout_SynchroNewPicture( p_sys->p_synchro,
p_sys->p_info->current_picture->flags & PIC_MASK_CODING_TYPE,
p_sys->p_info->current_picture->nb_fields,
0, 0, p_sys->i_current_rate );
if( p_sys->b_skip )
{
vout_SynchroTrash( p_sys->p_synchro );
}
else
{
vout_SynchroDecode( p_sys->p_synchro );
}
break;
case STATE_PICTURE:
{
uint8_t *buf[3];
mtime_t i_pts;
buf[0] = buf[1] = buf[2] = NULL;
if ( p_sys->b_after_sequence_header &&
((p_sys->p_info->current_picture->flags &
PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_P) )
{
/* Intra-slice refresh. Simulate a blank I picture. */
msg_Dbg( p_dec, "intra-slice refresh stream" );
vout_SynchroNewPicture( p_sys->p_synchro,
I_CODING_TYPE, 2, 0, 0, p_sys->i_current_rate );
vout_SynchroDecode( p_sys->p_synchro );
vout_SynchroEnd( p_sys->p_synchro, I_CODING_TYPE, 0 );
p_sys->b_slice_i = 1;
}
p_sys->b_after_sequence_header = 0;
#ifdef PIC_FLAG_PTS
i_pts = p_sys->p_info->current_picture->flags & PIC_FLAG_PTS ?
( ( p_sys->p_info->current_picture->pts ==
(uint32_t)p_sys->i_current_pts ) ?
p_sys->i_current_pts : p_sys->i_previous_pts ) : 0;
#else /* New interface */
i_pts = p_sys->p_info->current_picture->flags & PIC_FLAG_TAGS ?
( ( p_sys->p_info->current_picture->tag ==
(uint32_t)p_sys->i_current_pts ) ?
p_sys->i_current_pts : p_sys->i_previous_pts ) : 0;
#endif
/* Hack to handle demuxers which only have DTS timestamps */
if( !i_pts && !p_block->i_pts && p_block->i_dts > 0 )
{
if( p_sys->p_info->sequence->flags & SEQ_FLAG_LOW_DELAY ||
(p_sys->p_info->current_picture->flags &
PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_B )
{
i_pts = p_block->i_dts;
}
}
p_block->i_pts = p_block->i_dts = 0;
/* End hack */
vout_SynchroNewPicture( p_sys->p_synchro,
p_sys->p_info->current_picture->flags & PIC_MASK_CODING_TYPE,
p_sys->p_info->current_picture->nb_fields, i_pts,
0, p_sys->i_current_rate );
if ( !(p_sys->b_slice_i
&& ((p_sys->p_info->current_picture->flags
& PIC_MASK_CODING_TYPE) == P_CODING_TYPE))
&& !vout_SynchroChoose( p_sys->p_synchro,
p_sys->p_info->current_picture->flags
& PIC_MASK_CODING_TYPE,
/*FindVout(p_dec)->render_time*/ 0 /*FIXME*/ ) )
{
mpeg2_skip( p_sys->p_mpeg2dec, 1 );
p_sys->b_skip = 1;
vout_SynchroTrash( p_sys->p_synchro );
mpeg2_set_buf( p_sys->p_mpeg2dec, buf, NULL );
}
else
{
mpeg2_skip( p_sys->p_mpeg2dec, 0 );
p_sys->b_skip = 0;
vout_SynchroDecode( p_sys->p_synchro );
if( (p_pic = GetNewPicture( p_dec, buf )) == NULL )
{
block_Release( p_block );
return NULL;
}
p_sys->p_mpeg2dec->ptr_forward_ref_picture = p_sys->p_mpeg2dec->fbuf[2]->id;
p_sys->p_mpeg2dec->ptr_backward_ref_picture = p_sys->p_mpeg2dec->fbuf[1]->id;
if ((p_sys->p_info->current_picture->flags & PIC_MASK_CODING_TYPE) != B_CODING_TYPE)
{
//if (p_sys->p_mpeg2dec->ptr_forward_ref_picture &&
// p_sys->p_mpeg2dec->ptr_forward_ref_picture != picture->backward_reference_frame)
// p_pic->forward_reference_frame->free (p_pic->forward_reference_frame);
p_sys->p_mpeg2dec->ptr_forward_ref_picture =
p_sys->p_mpeg2dec->ptr_backward_ref_picture;
p_sys->p_mpeg2dec->ptr_backward_ref_picture = (void *)p_pic;
}
mpeg2_set_buf( p_sys->p_mpeg2dec, buf, p_pic );
}
}
break;
case STATE_END:
case STATE_SLICE:
p_pic = NULL;
if( p_sys->p_info->display_fbuf
&& p_sys->p_info->display_fbuf->id )
{
p_pic = (picture_t *)p_sys->p_info->display_fbuf->id;
vout_SynchroEnd( p_sys->p_synchro,
p_sys->p_info->display_picture->flags
& PIC_MASK_CODING_TYPE,
p_sys->b_garbage_pic );
p_sys->b_garbage_pic = 0;
if ( p_sys->p_picture_to_destroy != p_pic )
{
p_pic->date = vout_SynchroDate( p_sys->p_synchro );
}
else
{
p_sys->p_picture_to_destroy = NULL;
p_pic->date = 0;
}
}
if( p_sys->p_info->discard_fbuf &&
p_sys->p_info->discard_fbuf->id )
{
p_dec->pf_picture_unlink( p_dec, p_sys->p_info->discard_fbuf->id );
}
/* For still frames */
//if( state == STATE_END && p_pic ) p_pic->b_force = VLC_TRUE;
if( p_pic )
{
#if 0
/* Avoid frames with identical timestamps.
* Especially needed for still frames in DVD menus. */
if( p_sys->i_last_frame_pts == p_pic->date ) p_pic->date++;
p_sys->i_last_frame_pts = p_pic->date;
#endif
return p_pic;
}
break;
case STATE_INVALID:
{
uint8_t *buf[3];
buf[0] = buf[1] = buf[2] = NULL;
msg_Warn( p_dec, "invalid picture encountered" );
if ( ( p_sys->p_info->current_picture == NULL ) ||
( ( p_sys->p_info->current_picture->flags &
PIC_MASK_CODING_TYPE) != B_CODING_TYPE ) )
{
if( p_sys->p_synchro ) vout_SynchroReset( p_sys->p_synchro );
}
mpeg2_skip( p_sys->p_mpeg2dec, 1 );
p_sys->b_skip = 1;
if( p_sys->p_info->current_fbuf &&
p_sys->p_info->current_fbuf->id )
{
p_sys->b_garbage_pic = 1;
p_pic = p_sys->p_info->current_fbuf->id;
}
else if( !p_sys->p_info->sequence )
{
break;
}
else
{
if( (p_pic = GetNewPicture( p_dec, buf )) == NULL )
break;
mpeg2_set_buf( p_sys->p_mpeg2dec, buf, p_pic );
}
p_sys->p_picture_to_destroy = p_pic;
memset( p_pic->p[0].p_pixels, 0,
p_sys->p_info->sequence->width
* p_sys->p_info->sequence->height );
memset( p_pic->p[1].p_pixels, 0x80,
p_sys->p_info->sequence->width
* p_sys->p_info->sequence->height / 4 );
memset( p_pic->p[2].p_pixels, 0x80,
p_sys->p_info->sequence->width
* p_sys->p_info->sequence->height / 4 );
if( p_sys->b_slice_i )
{
vout_SynchroNewPicture( p_sys->p_synchro,
I_CODING_TYPE, 2, 0, 0, p_sys->i_current_rate );
vout_SynchroDecode( p_sys->p_synchro );
vout_SynchroEnd( p_sys->p_synchro, I_CODING_TYPE, 0 );
}
break;
}
default:
break;
}
}
return NULL;
}
/*****************************************************************************
* CloseDecoder: libmpeg2 decoder destruction
*****************************************************************************/
static void CloseDecoder( vlc_object_t *p_this )
{
decoder_t *p_dec = (decoder_t *)p_this;
decoder_sys_t *p_sys = p_dec->p_sys;
FILE *f_wd_dec;
if( p_sys->p_synchro ) vout_SynchroRelease( p_sys->p_synchro );
if( p_sys->p_mpeg2dec ) mpeg2_close( p_sys->p_mpeg2dec );
f_wd_dec = fopen("/vlc/dec_pid", "w");
if (f_wd_dec != NULL)
{
fprintf(f_wd_dec, "0\n");
fflush(f_wd_dec);
fclose(f_wd_dec);
}
free( p_sys );
}
static double get_aspect_ratio( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
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( !p_sys->p_mpeg2dec->decoder.mpeg1 )
{
/* these hardcoded values are defined on mpeg2 standard for
* aspect ratio. other values are reserved or forbidden. */
switch( p_sys->p_mpeg2dec->decoder.aspect_ratio_information )
{
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)p_sys->p_mpeg2dec->decoder.width/(double)p_sys->p_mpeg2dec->decoder.height;
break;
}
}
else
{
/* mpeg1 constants refer to pixel aspect ratio */
ratio = (double)p_sys->p_mpeg2dec->decoder.width/(double)p_sys->p_mpeg2dec->decoder.height;
ratio /= mpeg1_pel_ratio[p_sys->p_mpeg2dec->decoder.aspect_ratio_information];
}
return ratio;
}
/*****************************************************************************
* GetNewPicture: Get a new picture from the vout and set the buf struct
*****************************************************************************/
static picture_t *GetNewPicture( decoder_t *p_dec, uint8_t **pp_buf )
{
//msg_Dbg(p_dec, "GetNewPicture Entering");
decoder_sys_t *p_sys = p_dec->p_sys;
picture_t *p_pic;
static int nbpic = 0;
p_dec->fmt_out.video.i_width = p_sys->p_info->sequence->width;
p_dec->fmt_out.video.i_height = p_sys->p_info->sequence->height;
p_dec->fmt_out.video.i_aspect = p_sys->i_aspect;
if( p_sys->p_info->sequence->frame_period > 0 )
{
p_dec->fmt_out.video.i_frame_rate =
(uint32_t)( (uint64_t)1001000000 * 27 /
p_sys->p_info->sequence->frame_period );
p_dec->fmt_out.video.i_frame_rate_base = 1001;
}
p_dec->fmt_out.i_codec =
( p_sys->p_info->sequence->chroma_height <
p_sys->p_info->sequence->height ) ?
VLC_FOURCC('I','4','2','0') : VLC_FOURCC('I','4','2','2');
#if 0
p_sys->f_wd_nb = fopen("/vlc/dec_nb", "w");
if (p_sys->f_wd_nb != NULL)
{
// fprintf(p_sys->f_wd_nb, "%d\n", mdate());
fprintf(p_sys->f_wd_nb, "%s\n", mdate());
fflush(p_sys->f_wd_nb);
}
#endif
p_pic = p_dec->pf_vout_buffer_new( p_dec );
if( p_pic == NULL ) return NULL;
p_pic->b_progressive = p_sys->p_info->current_picture != NULL ?
p_sys->p_info->current_picture->flags & PIC_FLAG_PROGRESSIVE_FRAME : 1;
p_pic->b_top_field_first = p_sys->p_info->current_picture != NULL ?
p_sys->p_info->current_picture->flags & PIC_FLAG_TOP_FIELD_FIRST : 1;
p_pic->i_nb_fields = p_sys->p_info->current_picture != NULL ?
p_sys->p_info->current_picture->nb_fields : 2;
p_pic->format.i_frame_rate = p_dec->fmt_out.video.i_frame_rate;
p_pic->format.i_frame_rate_base = p_dec->fmt_out.video.i_frame_rate_base;
p_dec->pf_picture_link( p_dec, p_pic );
pp_buf[0] = p_pic->p[0].p_pixels;
pp_buf[1] = p_pic->p[1].p_pixels;
pp_buf[2] = p_pic->p[2].p_pixels;
/* let driver ensure this image has the right format */
#if 0
this->driver->update_frame_format( p_pic->p_sys->p_vout, p_pic,
p_dec->fmt_out.video.i_width,
p_dec->fmt_out.video.i_height,
p_dec->fmt_out.video.i_aspect,
format, flags);
#endif
mpeg2_xxmc_choose_coding( p_dec, &p_sys->p_mpeg2dec->decoder, p_pic,
get_aspect_ratio(p_dec), 0 );
return p_pic;
}
......@@ -15,3 +15,10 @@ SOURCES_glx = \
xcommon.c \
xcommon.h \
$(NULL)
SOURCES_xvmc = \
xvmc.c \
xcommon.c \
xcommon.h \
$(NULL)
......@@ -63,7 +63,7 @@
# include <X11/extensions/dpms.h>
#endif
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
# include <X11/extensions/Xv.h>
# include <X11/extensions/Xvlib.h>
#endif
......@@ -80,6 +80,11 @@
# include <X11/extensions/xf86vmode.h>
#endif
#ifdef MODULE_NAME_IS_xvmc
# include <X11/extensions/vldXvMC.h>
# include "../../codec/xvmc/accel_xvmc.h"
#endif
#include "xcommon.h"
/*****************************************************************************
......@@ -119,7 +124,7 @@ static void CreateCursor ( vout_thread_t * );
static void DestroyCursor ( vout_thread_t * );
static void ToggleCursor ( vout_thread_t * );
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
static int XVideoGetPort ( vout_thread_t *, vlc_fourcc_t, vlc_fourcc_t * );
static void XVideoReleasePort( vout_thread_t *, int );
#endif
......@@ -129,6 +134,12 @@ static void SetPalette ( vout_thread_t *,
uint16_t *, uint16_t *, uint16_t * );
#endif
#ifdef MODULE_NAME_IS_xvmc
static void RenderVideo ( vout_thread_t *, picture_t * );
static int xvmc_check_yv12( Display *display, XvPortID port );
static void xvmc_update_XV_DOUBLE_BUFFER( vout_thread_t *p_vout );
#endif
static void TestNetWMSupport( vout_thread_t * );
static int ConvertKey( int );
......@@ -148,8 +159,10 @@ int E_(Activate) ( vlc_object_t *p_this )
vout_thread_t *p_vout = (vout_thread_t *)p_this;
char * psz_display;
vlc_value_t val;
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvmc)
char *psz_value;
#endif
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
char * psz_chroma;
vlc_fourcc_t i_chroma = 0;
vlc_bool_t b_chroma = 0;
......@@ -158,7 +171,11 @@ int E_(Activate) ( vlc_object_t *p_this )
p_vout->pf_init = InitVideo;
p_vout->pf_end = EndVideo;
p_vout->pf_manage = ManageVideo;
#ifdef MODULE_NAME_IS_xvmc
p_vout->pf_render = RenderVideo;
#else
p_vout->pf_render = NULL;
#endif
p_vout->pf_display = DisplayVideo;
p_vout->pf_control = Control;
......@@ -194,7 +211,7 @@ int E_(Activate) ( vlc_object_t *p_this )
/* Get a screen ID matching the XOpenDisplay return value */
p_vout->p_sys->i_screen = DefaultScreen( p_vout->p_sys->p_display );
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
psz_chroma = config_GetPsz( p_vout, "xvideo-chroma" );
if( psz_chroma )
{
......@@ -298,6 +315,60 @@ int E_(Activate) ( vlc_object_t *p_this )
TestNetWMSupport( p_vout );
#ifdef MODULE_NAME_IS_xvmc
p_vout->p_sys->p_last_subtitle_save = NULL;
psz_value = config_GetPsz( p_vout, "xvmc-deinterlace-mode" );
/* Look what method was requested */
//var_Create( p_vout, "xvmc-deinterlace-mode", VLC_VAR_STRING );
//var_Change( p_vout, "xvmc-deinterlace-mode", VLC_VAR_INHERITVALUE, &val, NULL );
if( psz_value )
{
if( (strcmp(psz_value, "bob") == 0) ||
(strcmp(psz_value, "blend") == 0) )
p_vout->p_sys->xvmc_deinterlace_method = 2;
else if (strcmp(psz_value, "discard") == 0)
p_vout->p_sys->xvmc_deinterlace_method = 1;
else
p_vout->p_sys->xvmc_deinterlace_method = 0;
free(psz_value );
}
else
p_vout->p_sys->xvmc_deinterlace_method = 0;
/* Look what method was requested */
//var_Create( p_vout, "xvmc-crop-style", VLC_VAR_STRING );
//var_Change( p_vout, "xvmc-crop-style", VLC_VAR_INHERITVALUE, &val, NULL );
psz_value = config_GetPsz( p_vout, "xvmc-crop-style" );
if( psz_value )
{
if( strncmp( psz_value, "eq", 2 ) == 0 )
p_vout->p_sys->xvmc_crop_style = 1;
else if( strncmp( psz_value, "4-16", 4 ) == 0)
p_vout->p_sys->xvmc_crop_style = 2;
else if( strncmp( psz_value, "16-4", 4 ) == 0)
p_vout->p_sys->xvmc_crop_style = 3;
else
p_vout->p_sys->xvmc_crop_style = 0;
free( psz_value );
}
else
p_vout->p_sys->xvmc_crop_style = 0;
msg_Dbg(p_vout, "Deinterlace = %d", p_vout->p_sys->xvmc_deinterlace_method);
msg_Dbg(p_vout, "Crop = %d", p_vout->p_sys->xvmc_crop_style);
if( !checkXvMCCap( p_vout ) )
{
msg_Err( p_vout, "no XVMC capability found" );
E_(Deactivate)( p_vout );
return VLC_EGENERIC;
}
sub_pic.p_sys = NULL;
p_vout->p_sys->last_date = 0;
#endif
/* Variable to indicate if the window should be on top of others */
/* Trigger a callback right now */
var_Get( p_vout, "video-on-top", &val );
......@@ -335,19 +406,271 @@ void E_(Deactivate) ( vlc_object_t *p_this )
}
#elif defined(MODULE_NAME_IS_xvideo)
XVideoReleasePort( p_vout, p_vout->p_sys->i_xvport );
#elif defined(MODULE_NAME_IS_xvmc)
if( p_vout->p_sys->xvmc_cap )
{
xvmc_context_writer_lock( &p_vout->p_sys->xvmc_lock );
xxmc_dispose_context( p_vout );
if( p_vout->p_sys->old_subpic )
{
xxmc_xvmc_free_subpicture( p_vout, p_vout->p_sys->old_subpic );
p_vout->p_sys->old_subpic = NULL;
}
if( p_vout->p_sys->new_subpic )
{
xxmc_xvmc_free_subpicture( p_vout, p_vout->p_sys->new_subpic );
p_vout->p_sys->new_subpic = NULL;
}
free( p_vout->p_sys->xvmc_cap );
xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
}
#endif
DestroyCursor( p_vout );
EnableXScreenSaver( p_vout );
DestroyWindow( p_vout, &p_vout->p_sys->original_window );
XCloseDisplay( p_vout->p_sys->p_display );
/* Destroy structure */
vlc_mutex_destroy( &p_vout->p_sys->lock );
#ifdef MODULE_NAME_IS_xvmc
free_context_lock( &p_vout->p_sys->xvmc_lock );
#endif
free( p_vout->p_sys );
}
#ifdef MODULE_NAME_IS_xvmc
#define XINE_IMGFMT_YV12 (('2'<<24)|('1'<<16)|('V'<<8)|'Y')
/* called xlocked */
static int xvmc_check_yv12( Display *display, XvPortID port )
{
XvImageFormatValues *formatValues;
int formats;
int i;
formatValues = XvListImageFormats( display, port, &formats );
for( i = 0; i < formats; i++ )
{
if( ( formatValues[i].id == XINE_IMGFMT_YV12 ) &&
( !( strncmp( formatValues[i].guid, "YV12", 4 ) ) ) )
{
XFree (formatValues);
return 0;
}
}
XFree (formatValues);
return 1;
}
static void xvmc_sync_surface( vout_thread_t *p_vout, XvMCSurface * srf )
{
XvMCSyncSurface( p_vout->p_sys->p_display, srf );
}
static void xvmc_update_XV_DOUBLE_BUFFER( vout_thread_t *p_vout )
{
Atom atom;
int xv_double_buffer;
xv_double_buffer = 1;
XLockDisplay( p_vout->p_sys->p_display );
atom = XInternAtom( p_vout->p_sys->p_display, "XV_DOUBLE_BUFFER", False );
#if 0
XvSetPortAttribute (p_vout->p_sys->p_display, p_vout->p_sys->i_xvport, atom, xv_double_buffer);
#endif
XvMCSetAttribute( p_vout->p_sys->p_display, &p_vout->p_sys->context, atom, xv_double_buffer );
XUnlockDisplay( p_vout->p_sys->p_display );
//xprintf(this->xine, XINE_VERBOSITY_DEBUG,
// "video_out_xxmc: double buffering mode = %d\n", xv_double_buffer);
}
static void RenderVideo( vout_thread_t *p_vout, picture_t *p_pic )
{
vlc_xxmc_t *xxmc = NULL;
vlc_mutex_lock( &p_vout->p_sys->lock );
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
xxmc = &p_pic->p_sys->xxmc_data;
if( (!xxmc->decoded ||
!xxmc_xvmc_surface_valid( p_vout, p_pic->p_sys->xvmc_surf )) )
{
vlc_mutex_unlock( &p_vout->p_sys->lock );
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
return;
}
vlc_mutex_lock( &p_vout->lastsubtitle_lock );
if (p_vout->p_last_subtitle != NULL)
{
if( p_vout->p_sys->p_last_subtitle_save != p_vout->p_last_subtitle )
{
p_vout->p_sys->new_subpic =
xxmc_xvmc_alloc_subpicture( p_vout, &p_vout->p_sys->context,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height,
p_vout->p_sys->xvmc_cap[p_vout->p_sys->xvmc_cur_cap].subPicType.id );
if (p_vout->p_sys->new_subpic)
{
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
XvMCClearSubpicture( p_vout->p_sys->p_display,
p_vout->p_sys->new_subpic,
0,
0,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height,
0x00 );
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
clear_xx44_palette( &p_vout->p_sys->palette );
if( sub_pic.p_sys == NULL )
{
sub_pic.p_sys = malloc( sizeof( picture_sys_t ) );
if( sub_pic.p_sys != NULL )
{
sub_pic.p_sys->p_vout = p_vout;
sub_pic.p_sys->xvmc_surf = NULL;
sub_pic.p_sys->p_image = p_vout->p_sys->subImage;
}
}
sub_pic.p_sys->p_image = p_vout->p_sys->subImage;
sub_pic.p->p_pixels = sub_pic.p_sys->p_image->data;
sub_pic.p->i_pitch = p_vout->output.i_width;
memset( p_vout->p_sys->subImage->data, 0,
(p_vout->p_sys->subImage->width * p_vout->p_sys->subImage->height) );
if (p_vout->p_last_subtitle != NULL)
{
blend_xx44( p_vout->p_sys->subImage->data,
p_vout->p_last_subtitle,
p_vout->p_sys->subImage->width,
p_vout->p_sys->subImage->height,
p_vout->p_sys->subImage->width,
&p_vout->p_sys->palette,
(p_vout->p_sys->subImage->id == FOURCC_IA44) );
}
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
XvMCCompositeSubpicture( p_vout->p_sys->p_display,
p_vout->p_sys->new_subpic,
p_vout->p_sys->subImage,
0, /* overlay->x */
0, /* overlay->y */
p_vout->output.i_width, /* overlay->width, */
p_vout->output.i_height, /* overlay->height */
0, /* overlay->x */
0 ); /*overlay->y */
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
if (p_vout->p_sys->old_subpic)
{
xxmc_xvmc_free_subpicture( p_vout,
p_vout->p_sys->old_subpic);
p_vout->p_sys->old_subpic = NULL;
}
if (p_vout->p_sys->new_subpic)
{
p_vout->p_sys->old_subpic = p_vout->p_sys->new_subpic;
p_vout->p_sys->new_subpic = NULL;
xx44_to_xvmc_palette( &p_vout->p_sys->palette,
p_vout->p_sys->xvmc_palette,
0,
p_vout->p_sys->old_subpic->num_palette_entries,
p_vout->p_sys->old_subpic->entry_bytes,
p_vout->p_sys->old_subpic->component_order );
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
XvMCSetSubpicturePalette( p_vout->p_sys->p_display,
p_vout->p_sys->old_subpic,
p_vout->p_sys->xvmc_palette );
XvMCFlushSubpicture( p_vout->p_sys->p_display,
p_vout->p_sys->old_subpic);
XvMCSyncSubpicture( p_vout->p_sys->p_display,
p_vout->p_sys->old_subpic );
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
}
XVMCLOCKDISPLAY( p_vout->p_sys->p_display);
if (p_vout->p_sys->xvmc_backend_subpic )
{
XvMCBlendSubpicture( p_vout->p_sys->p_display,
p_pic->p_sys->xvmc_surf,
p_vout->p_sys->old_subpic,
0,
0,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height,
0,
0,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height );
}
else
{
XvMCBlendSubpicture2( p_vout->p_sys->p_display,
p_pic->p_sys->xvmc_surf,
p_pic->p_sys->xvmc_surf,
p_vout->p_sys->old_subpic,
0,
0,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height,
0,
0,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height );
}
XVMCUNLOCKDISPLAY(p_vout->p_sys->p_display);
}
}
else
{
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
if( p_vout->p_sys->xvmc_backend_subpic )
{
XvMCBlendSubpicture( p_vout->p_sys->p_display,
p_pic->p_sys->xvmc_surf,
p_vout->p_sys->old_subpic,
0, 0,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height,
0, 0,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height );
}
else
{
XvMCBlendSubpicture2( p_vout->p_sys->p_display,
p_pic->p_sys->xvmc_surf,
p_pic->p_sys->xvmc_surf,
p_vout->p_sys->old_subpic,
0, 0,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height,
0, 0,
p_vout->p_sys->xvmc_width,
p_vout->p_sys->xvmc_height );
}
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
}
}
p_vout->p_sys->p_last_subtitle_save = p_vout->p_last_subtitle;
vlc_mutex_unlock( &p_vout->lastsubtitle_lock );
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
vlc_mutex_unlock( &p_vout->p_sys->lock );
}
#endif
/*****************************************************************************
* InitVideo: initialize X11 video thread output method
*****************************************************************************
......@@ -361,7 +684,7 @@ static int InitVideo( vout_thread_t *p_vout )
I_OUTPUTPICTURES = 0;
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
/* Initialize the output structure; we already found an XVideo port,
* and the corresponding chroma we will be using. Since we can
* arbitrary scale, stick to the coordinates and aspect. */
......@@ -506,11 +829,122 @@ static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
vlc_mutex_lock( &p_vout->p_sys->lock );
#ifdef MODULE_NAME_IS_xvmc
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
vlc_xxmc_t *xxmc = &p_picture->p_sys->xxmc_data;
if( !xxmc->decoded ||
!xxmc_xvmc_surface_valid( p_vout, p_picture->p_sys->xvmc_surf ) )
{
msg_Dbg( p_vout, "DisplayVideo decoded=%d\tsurfacevalid=%d",
xxmc->decoded,
xxmc_xvmc_surface_valid( p_vout, p_picture->p_sys->xvmc_surf ) );
vlc_mutex_unlock( &p_vout->p_sys->lock );
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
return;
}
src_width = p_vout->output.i_width;
src_height = p_vout->output.i_height;
if( p_vout->p_sys->xvmc_crop_style == 1 )
{
src_x = 20;
src_y = 20;
src_width -= 40;
src_height -= 40;
}
else if( p_vout->p_sys->xvmc_crop_style == 2 )
{
src_x = 20;
src_y = 40;
src_width -= 40;
src_height -= 80;
}
else if( p_vout->p_sys->xvmc_crop_style == 3 )
{
src_x = 40;
src_y = 20;
src_width -= 80;
src_height -= 40;
}
else
{
src_x = 0;
src_y = 0;
}
if( p_vout->p_sys->xvmc_deinterlace_method > 0 )
{ /* BOB DEINTERLACE */
if( (p_picture->p_sys->nb_display == 0) ||
(p_vout->p_sys->xvmc_deinterlace_method == 1) )
{
first_field = (p_picture->b_top_field_first) ?
XVMC_BOTTOM_FIELD : XVMC_TOP_FIELD;
}
else
{
first_field = (p_picture->b_top_field_first) ?
XVMC_TOP_FIELD : XVMC_BOTTOM_FIELD;
}
}
else
{
first_field = XVMC_FRAME_PICTURE;
}
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
XvMCFlushSurface( p_vout->p_sys->p_display, p_picture->p_sys->xvmc_surf );
/* XvMCSyncSurface(p_vout->p_sys->p_display, p_picture->p_sys->xvmc_surf); */
XvMCPutSurface( p_vout->p_sys->p_display,
p_picture->p_sys->xvmc_surf,
p_vout->p_sys->p_win->video_window,
src_x,
src_y,
src_width,
src_height,
0 /*dest_x*/,
0 /*dest_y*/,
i_width,
i_height,
first_field);
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
if( p_vout->p_sys->xvmc_deinterlace_method == 2 )
{ /* BOB DEINTERLACE */
if( p_picture->p_sys->nb_display == 0 )/* && ((t2-t1) < 15000)) */
{
mtime_t last_date = p_picture->date;
vlc_mutex_lock( &p_vout->picture_lock );
if( !p_vout->p_sys->last_date )
{
p_picture->date += 20000;
}
else
{
p_picture->date = ((3 * p_picture->date -
p_vout->p_sys->last_date) / 2 );
}
p_vout->p_sys->last_date = last_date;
p_picture->b_force = 1;
p_picture->p_sys->nb_display = 1;
vlc_mutex_unlock( &p_vout->picture_lock );
}
else
{
p_picture->p_sys->nb_display = 0;
p_picture->b_force = 0;
}
}
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
#endif
#ifdef HAVE_SYS_SHM_H
if( p_vout->p_sys->b_shm )
{
/* Display rendered image using shared memory extension */
# ifdef MODULE_NAME_IS_xvideo
# if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
XvShmPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
p_vout->p_sys->p_win->video_window,
p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
......@@ -536,7 +970,7 @@ static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
#endif /* HAVE_SYS_SHM_H */
{
/* Use standard XPutImage -- this is gonna be slow ! */
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
XvPutImage( p_vout->p_sys->p_display, p_vout->p_sys->i_xvport,
p_vout->p_sys->p_win->video_window,
p_vout->p_sys->p_win->gc, p_pic->p_sys->p_image,
......@@ -577,6 +1011,10 @@ static int ManageVideo( vout_thread_t *p_vout )
vlc_mutex_lock( &p_vout->p_sys->lock );
#ifdef MODULE_NAME_IS_xvmc
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
#endif
/* Handle events from the owner window */
if( p_vout->p_sys->p_win->owner_window )
{
......@@ -948,8 +1386,11 @@ static int ManageVideo( vout_thread_t *p_vout )
}
}
vlc_mutex_unlock( &p_vout->p_sys->lock );
#ifdef MODULE_NAME_IS_xvmc
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
#endif
vlc_mutex_unlock( &p_vout->p_sys->lock );
return 0;
}
......@@ -1273,7 +1714,7 @@ static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
{
#ifndef MODULE_NAME_IS_glx
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
int i_plane;
#endif
......@@ -1286,6 +1727,15 @@ static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
return -1;
}
#ifdef MODULE_NAME_IS_xvmc
p_pic->p_sys->p_vout = p_vout;
p_pic->p_sys->xvmc_surf = NULL;
p_pic->p_sys->xxmc_data.decoded = 0;
p_pic->p_sys->xxmc_data.proc_xxmc_update_frame = xxmc_do_update_frame;
p_pic->p_accel_data = &p_pic->p_sys->xxmc_data;
p_pic->p_sys->nb_display = 0;
#endif
/* Fill in picture_t fields */
vout_InitPicture( VLC_OBJECT(p_vout), p_pic, p_vout->output.i_chroma,
p_vout->output.i_width, p_vout->output.i_height,
......@@ -1297,7 +1747,7 @@ static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
/* Create image using XShm extension */
p_pic->p_sys->p_image =
CreateShmImage( p_vout, p_vout->p_sys->p_display,
# ifdef MODULE_NAME_IS_xvideo
# if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
p_vout->p_sys->i_xvport,
VLC2X11_FOURCC(p_vout->output.i_chroma),
# else
......@@ -1314,7 +1764,7 @@ static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
/* Create image without XShm extension */
p_pic->p_sys->p_image =
CreateImage( p_vout, p_vout->p_sys->p_display,
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
p_vout->p_sys->i_xvport,
VLC2X11_FOURCC(p_vout->output.i_chroma),
p_pic->format.i_bits_per_pixel,
......@@ -1342,7 +1792,7 @@ static int NewPicture( vout_thread_t *p_vout, picture_t *p_pic )
switch( p_vout->output.i_chroma )
{
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
case VLC_FOURCC('I','4','2','0'):
case VLC_FOURCC('Y','V','1','2'):
case VLC_FOURCC('Y','2','1','1'):
......@@ -1437,6 +1887,14 @@ static void FreePicture( vout_thread_t *p_vout, picture_t *p_pic )
IMAGE_FREE( p_pic->p_sys->p_image );
}
#ifdef MODULE_NAME_IS_xvmc
if( p_pic->p_sys->xvmc_surf != NULL )
{
xxmc_xvmc_free_surface(p_vout , p_pic->p_sys->xvmc_surf);
p_pic->p_sys->xvmc_surf = NULL;
}
#endif
/* Do NOT use XFlush here ! */
XSync( p_vout->p_sys->p_display, False );
......@@ -1799,7 +2257,7 @@ static void ToggleCursor( vout_thread_t *p_vout )
}
}
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
/*****************************************************************************
* XVideoGetPort: get YUV12 port
*****************************************************************************/
......@@ -1851,8 +2309,11 @@ static int XVideoGetPort( vout_thread_t *p_vout,
}
i_selected_port = -1;
#ifdef MODULE_NAME_IS_xvmc
i_requested_adaptor = config_GetInt( p_vout, "xvmc-adaptor" );
#else
i_requested_adaptor = config_GetInt( p_vout, "xvideo-adaptor" );
#endif
for( i_adaptor = 0; i_adaptor < i_num_adaptors; ++i_adaptor )
{
XvImageFormatValues *p_formats;
......@@ -2151,6 +2612,9 @@ static IMAGE_TYPE * CreateShmImage( vout_thread_t *p_vout,
i_height = ( i_height + 15 ) >> 4 << 4;
i_width = ( i_width + 15 ) >> 4 << 4;
p_image = XvShmCreateImage( p_display, i_xvport, i_chroma, 0,
i_width, i_height, p_shm );
#elif defined(MODULE_NAME_IS_xvmc)
p_image = XvShmCreateImage( p_display, i_xvport, i_chroma, 0,
i_width, i_height, p_shm );
#else
......@@ -2381,11 +2845,16 @@ static int Control( vout_thread_t *p_vout, int i_query, va_list args )
if( !i_width ) i_width = p_vout->i_window_width;
if( !i_height ) i_height = p_vout->i_window_height;
#ifdef MODULE_NAME_IS_xvmc
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
#endif
/* Update dimensions */
XResizeWindow( p_vout->p_sys->p_display,
p_vout->p_sys->p_win->base_window,
i_width, i_height );
#ifdef MODULE_NAME_IS_xvmc
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
#endif
vlc_mutex_unlock( &p_vout->p_sys->lock );
return VLC_SUCCESS;
......@@ -2400,6 +2869,9 @@ static int Control( vout_thread_t *p_vout, int i_query, va_list args )
vlc_mutex_lock( &p_vout->p_sys->lock );
if( i_query == VOUT_REPARENT ) d = (Drawable)va_arg( args, int );
if( !d )
#ifdef MODULE_NAME_IS_xvmc
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
#endif
XReparentWindow( p_vout->p_sys->p_display,
p_vout->p_sys->original_window.base_window,
DefaultRootWindow( p_vout->p_sys->p_display ),
......@@ -2410,6 +2882,9 @@ static int Control( vout_thread_t *p_vout, int i_query, va_list args )
d, 0, 0);
XSync( p_vout->p_sys->p_display, False );
p_vout->p_sys->original_window.owner_window = 0;
#ifdef MODULE_NAME_IS_xvmc
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
#endif
vlc_mutex_unlock( &p_vout->p_sys->lock );
return vout_vaControlDefault( p_vout, i_query, args );
......@@ -2420,7 +2895,13 @@ static int Control( vout_thread_t *p_vout, int i_query, va_list args )
b_arg = va_arg( args, vlc_bool_t );
vlc_mutex_lock( &p_vout->p_sys->lock );
#ifdef MODULE_NAME_IS_xvmc
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
#endif
WindowOnTop( p_vout, b_arg );
#ifdef MODULE_NAME_IS_xvmc
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
#endif
vlc_mutex_unlock( &p_vout->p_sys->lock );
return VLC_SUCCESS;
......
......@@ -27,7 +27,7 @@
/*****************************************************************************
* Defines
*****************************************************************************/
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
# define IMAGE_TYPE XvImage
# define EXTRA_ARGS int i_xvport, int i_chroma, int i_bits_per_pixel
# define EXTRA_ARGS_SHM int i_xvport, int i_chroma, XShmSegmentInfo *p_shm
......@@ -51,6 +51,7 @@
VLC_FOURCC( i & 0xff, (i >> 8) & 0xff, (i >> 16) & 0xff, \
(i >> 24) & 0xff )
/*****************************************************************************
* x11_window_t: X11 window descriptor
*****************************************************************************
......@@ -106,7 +107,7 @@ struct vout_sys_t
vlc_bool_t b_shm; /* shared memory extension flag */
#endif
#ifdef MODULE_NAME_IS_xvideo
#if defined(MODULE_NAME_IS_xvideo) || defined(MODULE_NAME_IS_xvmc)
int i_xvport;
#else
Colormap colormap; /* colormap used (8bpp only) */
......@@ -149,6 +150,62 @@ struct vout_sys_t
GLXContext gwctx;
GLXWindow gwnd;
#endif
#ifdef MODULE_NAME_IS_xvmc
/* XvMC related stuff here */
xvmc_macroblocks_t macroblocks;
xvmc_capabilities_t *xvmc_cap;
unsigned int xvmc_num_cap;
unsigned int xvmc_max_subpic_x;
unsigned int xvmc_max_subpic_y;
int xvmc_eventbase;
int xvmc_errbase;
int hwSubpictures;
XvMCSubpicture *old_subpic;
XvMCSubpicture *new_subpic;
xx44_palette_t palette;
int first_overlay;
float cpu_saver;
int cpu_save_enabled;
int reverse_nvidia_palette;
int context_flags;
/*
* These variables are protected by the context lock:
*/
unsigned xvmc_cur_cap;
int xvmc_backend_subpic;
XvMCContext context;
int contextActive;
xvmc_surface_handler_t xvmc_surf_handler;
unsigned xvmc_mpeg;
unsigned xvmc_accel;
unsigned last_accel_request;
unsigned xvmc_width;
unsigned xvmc_height;
int have_xvmc_autopaint;
int xvmc_xoverlay_type;
int unsigned_intra;
/*
* Only creation and destruction of the below.
*/
char *xvmc_palette;
XvImage *subImage;
XShmSegmentInfo subShmInfo;
/*
* The mutex below is needed since XlockDisplay wasn't really enough
* to protect the XvMC Calls.
*/
context_lock_t xvmc_lock;
subpicture_t * p_last_subtitle_save;
int xvmc_deinterlace_method;
int xvmc_crop_style;
mtime_t last_date;
//alphablend_t alphablend_extra_data;
#endif
};
/*****************************************************************************
......@@ -164,6 +221,14 @@ struct picture_sys_t
#ifdef HAVE_SYS_SHM_H
XShmSegmentInfo shminfo; /* shared memory zone information */
#endif
#ifdef MODULE_NAME_IS_xvmc
XvMCSurface *xvmc_surf;
vlc_xxmc_t xxmc_data;
int last_sw_format;
vout_thread_t *p_vout;
int nb_display;
#endif
};
/*****************************************************************************
......@@ -174,6 +239,7 @@ struct picture_sys_t
*****************************************************************************/
#define MWM_HINTS_DECORATIONS (1L << 1)
#define PROP_MWM_HINTS_ELEMENTS 5
typedef struct mwmhints_t
{
uint32_t flags;
......@@ -181,7 +247,6 @@ typedef struct mwmhints_t
uint32_t decorations;
int32_t input_mode;
uint32_t status;
} mwmhints_t;
/*****************************************************************************
......@@ -189,7 +254,125 @@ typedef struct mwmhints_t
*****************************************************************************/
#ifdef MODULE_NAME_IS_xvideo
# define MAX_DIRECTBUFFERS 10
#elif defined(MODULE_NAME_IS_xvmc)
# define MAX_DIRECTBUFFERS 12
#else
# define MAX_DIRECTBUFFERS 2
#endif
/*****************************************************************************
* Xxmc defines
*****************************************************************************/
#ifdef MODULE_NAME_IS_xvmc
typedef struct
{ /* CLUT == Color LookUp Table */
uint8_t cb;
uint8_t cr;
uint8_t y;
uint8_t foo;
} clut_t;
#define XX44_PALETTE_SIZE 32
#define OVL_PALETTE_SIZE 256
#define XVMC_MAX_SURFACES 16
#define XVMC_MAX_SUBPICTURES 4
#define FOURCC_IA44 0x34344149
#define FOURCC_AI44 0x34344941
typedef struct
{
unsigned size;
unsigned max_used;
uint32_t cluts[XX44_PALETTE_SIZE];
/* cache palette entries for both colors and clip_colors */
int lookup_cache[OVL_PALETTE_SIZE*2];
} xx44_palette_t;
/*
* Functions to handle the vlc-specific palette.
*/
void clear_xx44_palette( xx44_palette_t *p );
/*
* Convert the xine-specific palette to something useful.
*/
void xx44_to_xvmc_palette( const xx44_palette_t *p,unsigned char *xvmc_palette,
unsigned first_xx44_entry, unsigned num_xx44_entries,
unsigned num_xvmc_components, char *xvmc_components );
typedef struct
{
vlc_macroblocks_t vlc_mc;
XvMCBlockArray blocks; /* pointer to memory for dct block array */
int num_blocks;
XvMCMacroBlock *macroblockptr; /* pointer to current macro block */
XvMCMacroBlock *macroblockbaseptr; /* pointer to base MacroBlock in MB array */
XvMCMacroBlockArray macro_blocks; /* pointer to memory for macroblock array */
int slices;
} xvmc_macroblocks_t;
typedef struct
{
unsigned int mpeg_flags;
unsigned int accel_flags;
unsigned int max_width;
unsigned int max_height;
unsigned int sub_max_width;
unsigned int sub_max_height;
int type_id;
XvImageFormatValues subPicType;
int flags;
} xvmc_capabilities_t;
typedef struct xvmc_surface_handler_s
{
XvMCSurface surfaces[XVMC_MAX_SURFACES];
int surfInUse[XVMC_MAX_SURFACES];
int surfValid[XVMC_MAX_SURFACES];
XvMCSubpicture subpictures[XVMC_MAX_SUBPICTURES];
int subInUse[XVMC_MAX_SUBPICTURES];
int subValid[XVMC_MAX_SUBPICTURES];
pthread_mutex_t mutex;
} xvmc_surface_handler_t;
typedef struct context_lock_s
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int num_readers;
} context_lock_t;
#define XVMCLOCKDISPLAY(display) XLockDisplay(display);
#define XVMCUNLOCKDISPLAY(display) XUnlockDisplay(display);
void xvmc_context_reader_unlock( context_lock_t *c );
void xvmc_context_reader_lock( context_lock_t *c );
void xvmc_context_writer_lock( context_lock_t *c );
void xvmc_context_writer_unlock( context_lock_t *c );
void free_context_lock( context_lock_t *c );
void xxmc_dispose_context( vout_thread_t *p_vout );
int xxmc_xvmc_surface_valid( vout_thread_t *p_vout, XvMCSurface *surf );
void xxmc_xvmc_free_surface( vout_thread_t *p_vout, XvMCSurface *surf );
void xvmc_vld_slice( picture_t *picture );
void xvmc_vld_frame( picture_t *picture );
void xxmc_do_update_frame( picture_t *picture, uint32_t width, uint32_t height,
double ratio, int format, int flags);
int checkXvMCCap( vout_thread_t *p_vout);
XvMCSubpicture *xxmc_xvmc_alloc_subpicture( vout_thread_t *p_vout,
XvMCContext *context, unsigned short width, unsigned short height,
int xvimage_id );
void xxmc_xvmc_free_subpicture( vout_thread_t *p_vout, XvMCSubpicture *sub );
void blend_xx44( uint8_t *dst_img, subpicture_t *sub_img, int dst_width,
int dst_height, int dst_pitch, xx44_palette_t *palette,int ia44);
#endif
/*****************************************************************************
* xvmc.c : XVMC plugin for vlc
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id$
*
* Authors: Shane Harper <shanegh@optusnet.com.au>
* Vincent Seguin <seguin@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* David Kennedy <dkennedy@tinytoad.com>
* Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
*
* This program 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.
*
* This program 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, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h> /* strerror() */
#include <vlc/vlc.h>
#include <vlc/intf.h>
#include <vlc/vout.h>
#include <vlc_keys.h>
#ifdef HAVE_MACHINE_PARAM_H
/* BSD */
# include <machine/param.h>
# include <sys/types.h> /* typedef ushort */
# include <sys/ipc.h>
#endif
#ifndef WIN32
# include <netinet/in.h> /* BSD: struct in_addr */
#endif
#ifdef HAVE_SYS_SHM_H
# include <sys/shm.h> /* shmget(), shmctl() */
#endif
#include <X11/Xlib.h>
#include <X11/Xmd.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#ifdef HAVE_SYS_SHM_H
# include <X11/extensions/XShm.h>
#endif
#ifdef DPMSINFO_IN_DPMS_H
# include <X11/extensions/dpms.h>
#endif
#include <X11/extensions/Xv.h>
#include <X11/extensions/Xvlib.h>
#include <X11/extensions/vldXvMC.h>
#include "../../codec/xxmc/accel_xvmc.h"
#include "xcommon.h"
#include "../../codec/spudec/spudec.h"
#include <unistd.h>
/* picture structure */
#define TOP_FIELD 1
#define BOTTOM_FIELD 2
#define FRAME_PICTURE 3
/* picture coding type */
#define I_TYPE 1
#define P_TYPE 2
#define B_TYPE 3
#define D_TYPE 4
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
extern int E_(Activate) ( vlc_object_t * );
extern void E_(Deactivate) ( vlc_object_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#define ADAPTOR_TEXT N_("XVMC adaptor number")
#define ADAPTOR_LONGTEXT N_( \
"If you graphics card provides several adaptors, this option allows you " \
"to choose which one will be used (you shouldn't have to change this).")
#define ALT_FS_TEXT N_("Alternate fullscreen method")
#define ALT_FS_LONGTEXT N_( \
"There are two ways to make a fullscreen window, unfortunately each one " \
"has its drawbacks.\n" \
"1) Let the window manager handle your fullscreen window (default), but " \
"things like taskbars will likely show on top of the video.\n" \
"2) Completely bypass the window manager, but then nothing will be able " \
"to show on top of the video.")
#define DISPLAY_TEXT N_("X11 display name")
#define DISPLAY_LONGTEXT N_( \
"Specify the X11 hardware display you want to use. By default VLC will " \
"use the value of the DISPLAY environment variable.")
#define CHROMA_TEXT N_("XVimage chroma format")
#define CHROMA_LONGTEXT N_( \
"Force the XVideo renderer to use a specific chroma format instead of " \
"trying to improve performances by using the most efficient one.")
#define SHM_TEXT N_("Use shared memory")
#define SHM_LONGTEXT N_( \
"Use shared memory to communicate between VLC and the X server.")
#define SCREEN_TEXT N_("Screen to be used for fullscreen mode.")
#define SCREEN_LONGTEXT N_( \
"Choose the screen you want to use in fullscreen mode. For instance " \
"set it to 0 for first screen, 1 for the second.")
#define MODE_TEXT N_("Deinterlace mode")
#define MODE_LONGTEXT N_("You can choose the default deinterlace mode")
#define CROP_TEXT N_("Crop")
#define CROP_LONGTEXT N_("You can choose the crop style to apply.")
vlc_module_begin();
set_shortname( "XVMC" );
add_string( "xvmc-display", NULL, NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT, VLC_TRUE );
add_integer( "xvmc-adaptor", -1, NULL, ADAPTOR_TEXT, ADAPTOR_LONGTEXT, VLC_TRUE );
add_bool( "xvmc-altfullscreen", 0, NULL, ALT_FS_TEXT, ALT_FS_LONGTEXT, VLC_TRUE );
add_string( "xvmc-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT, VLC_TRUE );
#ifdef HAVE_SYS_SHM_H
add_bool( "xvmc-shm", 1, NULL, SHM_TEXT, SHM_LONGTEXT, VLC_TRUE );
#endif
#ifdef HAVE_XINERAMA
add_integer ( "xvmc-xineramascreen", 0, NULL, SCREEN_TEXT, SCREEN_LONGTEXT, VLC_TRUE );
#endif
add_string( "xvmc-deinterlace-mode", "bob", NULL, MODE_TEXT, MODE_LONGTEXT, VLC_FALSE );
add_string( "xvmc-crop-style", "eq", NULL, CROP_TEXT, CROP_LONGTEXT, VLC_FALSE );
set_description( _("XVMC extension video output") );
set_capability( "video output", 160 );
set_callbacks( E_(Activate), E_(Deactivate) );
vlc_module_end();
/* following functions are local */
static unsigned accel_priority[] = {
VLC_XVMC_ACCEL_VLD,
};
#define NUM_ACCEL_PRIORITY (sizeof(accel_priority)/sizeof(accel_priority[0]))
/*
* Additional thread safety, since the plugin may decide to destroy a context
* while it's surfaces are still active in the video-out loop.
* When / If XvMC libs are reasonably thread-safe, the locks can be made
* more efficient by allowing multiple threads in that do not destroy
* the context or surfaces that may be active in other threads.
*/
static void init_context_lock( context_lock_t *c )
{
pthread_cond_init(&c->cond,NULL);
pthread_mutex_init(&c->mutex,NULL);
c->num_readers = 0;
}
void free_context_lock( context_lock_t *c )
{
pthread_mutex_destroy(&c->mutex);
pthread_cond_destroy(&c->cond);
}
void xvmc_context_reader_lock( context_lock_t *c )
{
pthread_mutex_lock(&c->mutex);
c->num_readers++;
pthread_mutex_unlock(&c->mutex);
}
void xvmc_context_reader_unlock( context_lock_t *c )
{
pthread_mutex_lock(&c->mutex);
if (c->num_readers > 0) {
if (--(c->num_readers) == 0) {
pthread_cond_broadcast(&c->cond);
}
}
pthread_mutex_unlock(&c->mutex);
}
void xvmc_context_writer_lock( context_lock_t *c )
{
pthread_mutex_lock(&c->mutex);
while(c->num_readers) {
pthread_cond_wait( &c->cond, &c->mutex );
}
}
void xvmc_context_writer_unlock( context_lock_t *c )
{
pthread_mutex_unlock( &c->mutex );
}
void clear_xx44_palette( xx44_palette_t *p )
{
register int i;
register uint32_t *cluts = p->cluts;
register int *ids = p->lookup_cache;
i= p->size;
while(i--)
*cluts++ = 0;
i = 2*OVL_PALETTE_SIZE;
while(i--)
*ids++ = -1;
p->max_used=1;
}
static void init_xx44_palette( xx44_palette_t *p, unsigned num_entries )
{
p->size = (num_entries > XX44_PALETTE_SIZE) ?
XX44_PALETTE_SIZE : num_entries;
}
static void dispose_xx44_palette(xx44_palette_t *p)
{
/* Nothing to do */
}
static void colorToPalette( const uint32_t *icolor, unsigned char *palette_p,
unsigned num_xvmc_components, char *xvmc_components )
{
const clut_t *color = (const clut_t *) icolor;
int i;
for (i=0; i<num_xvmc_components; ++i)
{
switch(xvmc_components[i])
{
case 'V': *palette_p = color->cr; break;
case 'U': *palette_p = color->cb; break;
case 'Y':
default: *palette_p = color->y; break;
}
*palette_p++;
}
}
void xx44_to_xvmc_palette( const xx44_palette_t *p,unsigned char *xvmc_palette,
unsigned first_xx44_entry, unsigned num_xx44_entries,
unsigned num_xvmc_components, char *xvmc_components )
{
int i;
const uint32_t *cluts = p->cluts + first_xx44_entry;
for( i=0; i<num_xx44_entries; ++i )
{
if( (cluts - p->cluts) < p->size )
{
colorToPalette( cluts++, xvmc_palette,
num_xvmc_components, xvmc_components );
xvmc_palette += num_xvmc_components;
}
}
}
static int xx44_paletteIndex( xx44_palette_t *p, int color, uint32_t clut )
{
int i;
uint32_t *cluts = p->cluts;
int tmp;
if( (tmp = p->lookup_cache[color]) >= 0 )
{
if (cluts[tmp] == clut)
return tmp;
}
for (i=0; i<p->max_used; ++i)
{
if (*cluts++ == clut) {
p->lookup_cache[color] = i;
return p->lookup_cache[color];
}
}
if( p->max_used == (p->size -1) )
{
//printf("video_out: Warning! Out of xx44 palette colors!\n");
return 1;
}
p->cluts[p->max_used] = clut;
p->lookup_cache[color] = p->max_used++;
return p->lookup_cache[color];
}
static void memblend_xx44( uint8_t *mem, uint8_t val,
size_t size, uint8_t mask )
{
uint8_t masked_val = val & mask;
if (size < 0)
return;
while(size--)
{
if( (*mem & mask) <= masked_val )
*mem = val;
mem++;
}
}
void blend_xx44( uint8_t *dst_img, subpicture_t *sub_img,
int dst_width, int dst_height, int dst_pitch,
xx44_palette_t *palette, int ia44 )
{
int src_width;
int src_height;
int mask;
int x_off;
int y_off;
int x, y;
uint8_t norm_pixel,clip_pixel;
uint8_t *dst_y;
uint8_t *dst;
uint8_t alphamask;
int clip_right;
int i_len, i_color;
uint16_t *p_source = NULL;
uint16_t i_colprecomp, i_destalpha;
if (!sub_img)
return;
src_width = sub_img->i_width;
src_height = sub_img->i_height;
x_off = sub_img->i_x;
y_off = sub_img->i_y;
alphamask = (ia44) ? 0x0F : 0xF0;
p_source = (uint16_t *)sub_img->p_sys->p_data;
i_colprecomp, i_destalpha;
dst_y = dst_img + dst_pitch*y_off + x_off;
if( (x_off + sub_img->i_width) <= dst_width )
clip_right = sub_img->i_width;
else
clip_right = dst_width - x_off;
if ((src_height + y_off) > dst_height)
src_height = dst_height - y_off;
for (y = 0; y < src_height; y++)
{
mask = !( (y < sub_img->p_sys->i_y_start) ||
(y >= sub_img->p_sys->i_y_end) );
dst = dst_y;
for (x = 0; x < src_width;)
{
i_color = *p_source & 0x3;
i_len = *p_source++ >> 2;
if( (i_len > 0) && ((x+i_len) <= src_width) )
{
/* Get the RLE part, then draw the line */
uint32_t color = (sub_img->p_sys->pi_yuv[i_color][0] << 16) |
(sub_img->p_sys->pi_yuv[i_color][1] << 0) |
(sub_img->p_sys->pi_yuv[i_color][2] << 8);
norm_pixel = (uint8_t)(
(xx44_paletteIndex( palette,i_color, color ) << 4) |
(sub_img->p_sys->pi_alpha[i_color] & 0x0F) );
clip_pixel = (uint8_t)(
(xx44_paletteIndex( palette,i_color + OVL_PALETTE_SIZE,
sub_img->p_sys->pi_yuv[i_color][0] ) << 4) |
(sub_img->p_sys->pi_alpha[i_color] & 0x0F));
if( !ia44 )
{
norm_pixel = ((norm_pixel & 0x0F) << 4) | ((norm_pixel & 0xF0) >> 4);
clip_pixel = ((clip_pixel & 0x0F) << 4) | ((clip_pixel & 0xF0) >> 4);
}
if( mask )
{
if( x < sub_img->p_sys->i_x_start )
{
if( (x + i_len) <= sub_img->p_sys->i_x_start )
{
memblend_xx44( dst, norm_pixel, i_len, alphamask );
dst += i_len;
}
else
{
memblend_xx44( dst, norm_pixel,
sub_img->p_sys->i_x_start - x,
alphamask );
dst += sub_img->p_sys->i_x_start - x;
i_len -= sub_img->p_sys->i_x_start - x;
if( i_len <= (sub_img->p_sys->i_x_end -
sub_img->p_sys->i_x_start) )
{
memblend_xx44( dst, clip_pixel,
i_len, alphamask);
dst += i_len;
}
else
{
memblend_xx44( dst, clip_pixel,
sub_img->p_sys->i_x_end -
sub_img->p_sys->i_x_start,
alphamask );
dst += (sub_img->p_sys->i_x_end -
sub_img->p_sys->i_x_start);
i_len -= (sub_img->p_sys->i_x_end -
sub_img->p_sys->i_x_start);
memblend_xx44( dst, norm_pixel,
i_len, alphamask );
dst += i_len;
}
}
}
else if( x < sub_img->p_sys->i_x_end )
{
if( i_len <= (sub_img->p_sys->i_x_end - x) )
{
memblend_xx44( dst, clip_pixel, i_len, alphamask);
dst += i_len;
}
else
{
memblend_xx44( dst, clip_pixel,
sub_img->p_sys->i_x_end - x,
alphamask);
dst += (sub_img->p_sys->i_x_end - x);
i_len -= (sub_img->p_sys->i_x_end - x);
memblend_xx44( dst, norm_pixel, i_len, alphamask);
dst += i_len;
}
}
else
{
memblend_xx44( dst, norm_pixel, i_len, alphamask );
dst += i_len;
}
}
else
{
memblend_xx44( dst, norm_pixel, i_len, alphamask );
dst += i_len;
}
}
else
{
return;
}
x += i_len;
}
dst_y += dst_pitch;
}
}
int xxmc_xvmc_surface_valid( vout_thread_t *p_vout, XvMCSurface *surf )
{
xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
unsigned int index = surf - handler->surfaces;
int ret;
if (index >= XVMC_MAX_SURFACES)
return 0;
pthread_mutex_lock(&handler->mutex);
ret = handler->surfValid[index];
pthread_mutex_unlock(&handler->mutex);
return ret;
}
static void xxmc_xvmc_dump_subpictures( vout_thread_t *p_vout )
{
int i;
xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
for( i=0; i < XVMC_MAX_SUBPICTURES; ++i )
{
msg_Dbg( p_vout, "handler in use %d, valid %d",
handler->subInUse[i],
handler->subValid[i]);
}
}
XvMCSubpicture *xxmc_xvmc_alloc_subpicture( vout_thread_t *p_vout,
XvMCContext *context, unsigned short width,
unsigned short height, int xvimage_id )
{
int i;
xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
int status;
pthread_mutex_lock(&handler->mutex);
/* xxmc_xvmc_dump_subpictures(p_vout); */
for( i=0; i<XVMC_MAX_SUBPICTURES; ++i )
{
if( handler->subValid[i] && !handler->subInUse[i] )
{
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
if( XvMCGetSubpictureStatus( p_vout->p_sys->p_display,
handler->subpictures + i,
&status ) )
{
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
continue;
}
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
if( status & XVMC_DISPLAYING )
continue;
handler->subInUse[i] = 1;
/* xxmc_xvmc_dump_subpictures(p_vout); */
pthread_mutex_unlock(&handler->mutex);
return (handler->subpictures + i);
}
}
for (i=0; i<XVMC_MAX_SUBPICTURES; ++i)
{
if( !handler->subInUse[i] )
{
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
if( Success != XvMCCreateSubpicture( p_vout->p_sys->p_display,
context,
handler->subpictures + i,
width, height, xvimage_id ) )
{
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
pthread_mutex_unlock( &handler->mutex );
return NULL;
}
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
msg_Dbg( p_vout, "video_out_xxmc: created subpicture %d\n", i );
handler->subInUse[i] = 1;
handler->subValid[i] = 1;
pthread_mutex_unlock( &handler->mutex );
return (handler->subpictures + i);
}
}
pthread_mutex_unlock( &handler->mutex );
return NULL;
}
void xxmc_xvmc_free_subpicture( vout_thread_t *p_vout, XvMCSubpicture *sub )
{
xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
unsigned int index = sub - handler->subpictures;
if( index >= XVMC_MAX_SUBPICTURES )
return;
pthread_mutex_lock( &handler->mutex );
handler->subInUse[index] = 0;
/* xxmc_xvmc_dump_subpictures(p_vout); */
pthread_mutex_unlock( &handler->mutex );
}
static void xxmc_xvmc_surface_handler_construct( vout_thread_t *p_vout )
{
int i;
xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
pthread_mutex_init( &handler->mutex, NULL );
for( i=0; i<XVMC_MAX_SURFACES; ++i )
{
handler->surfInUse[i] = 0;
handler->surfValid[i] = 0;
}
for( i=0; i<XVMC_MAX_SUBPICTURES; ++i )
{
handler->subInUse[i] = 0;
handler->subValid[i] = 0;
}
}
static void xxmc_xvmc_dump_surfaces( vout_thread_t *p_vout )
{
int i;
xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
for (i=0; i<XVMC_MAX_SURFACES; ++i)
{
msg_Dbg(p_vout, "surfaces in use %d, valid %d;",
handler->surfInUse[i],
handler->surfValid[i]);
}
}
void xxmc_xvmc_free_surface( vout_thread_t *p_vout, XvMCSurface *surf )
{
xvmc_surface_handler_t *handler = &p_vout->p_sys->xvmc_surf_handler;
unsigned int index = 0;
index = (surf - handler->surfaces);
if (index < XVMC_MAX_SURFACES)
{
pthread_mutex_lock(&handler->mutex);
msg_Dbg( p_vout,"free surface %d",index );
handler->surfInUse[index]--;
xxmc_xvmc_dump_surfaces(p_vout);
pthread_mutex_unlock(&handler->mutex);
}
}
int checkXvMCCap( vout_thread_t *p_vout )
{
int i_xvport = 0;
int numSurf = 0;
int numSub = 0;
int i,j;
XvMCSurfaceInfo *surfaceInfo =NULL;
XvMCSurfaceInfo *curInfo = NULL;
XvMCContext c;
xvmc_capabilities_t *curCap = NULL;
XvImageFormatValues *formatValues = NULL;
i_xvport = p_vout->p_sys->i_xvport;
p_vout->p_sys->xvmc_cap = 0;
init_context_lock( &p_vout->p_sys->xvmc_lock );
xvmc_context_writer_lock( &p_vout->p_sys->xvmc_lock );
p_vout->p_sys->old_subpic = NULL;
p_vout->p_sys->new_subpic = NULL;
p_vout->p_sys->contextActive = 0;
p_vout->p_sys->subImage = NULL;
p_vout->p_sys->hwSubpictures = 0;
p_vout->p_sys->xvmc_palette = NULL;
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
if( !XvMCQueryExtension( p_vout->p_sys->p_display,
&p_vout->p_sys->xvmc_eventbase,
&p_vout->p_sys->xvmc_errbase ) )
{
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
return VLC_EGENERIC;
}
msg_Dbg( p_vout,"XvMC extension found" );
surfaceInfo = XvMCListSurfaceTypes(p_vout->p_sys->p_display, i_xvport, &numSurf);
if( !surfaceInfo )
{
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
return VLC_EGENERIC;
}
p_vout->p_sys->xvmc_cap =
(xvmc_capabilities_t *) malloc( numSurf *
sizeof(xvmc_capabilities_t) );
if( !p_vout->p_sys->xvmc_cap )
{
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
return VLC_EGENERIC;
}
p_vout->p_sys->xvmc_num_cap = numSurf;
curInfo = surfaceInfo;
curCap = p_vout->p_sys->xvmc_cap;
msg_Dbg( p_vout,"found %d XvMC surface types", numSurf );
for( i=0; i< numSurf; ++i )
{
curCap->mpeg_flags = 0;
curCap->accel_flags = 0;
if( curInfo->chroma_format == XVMC_CHROMA_FORMAT_420 )
{
curCap->mpeg_flags |= ((curInfo->mc_type & XVMC_MPEG_1) ?
VLC_XVMC_MPEG_1 : 0);
curCap->mpeg_flags |= ((curInfo->mc_type & XVMC_MPEG_2) ?
VLC_XVMC_MPEG_2 : 0);
curCap->mpeg_flags |= ((curInfo->mc_type & XVMC_MPEG_4) ?
VLC_XVMC_MPEG_4 : 0);
curCap->accel_flags |= ((curInfo->mc_type & XVMC_VLD) ?
VLC_XVMC_ACCEL_VLD : 0);
curCap->accel_flags |= ((curInfo->mc_type & XVMC_IDCT) ?
VLC_XVMC_ACCEL_IDCT : 0);
curCap->accel_flags |= ((curInfo->mc_type & (XVMC_VLD | XVMC_IDCT)) ?
0 : VLC_XVMC_ACCEL_MOCOMP);
curCap->max_width = curInfo->max_width;
curCap->max_height = curInfo->max_height;
curCap->sub_max_width = curInfo->subpicture_max_width;
curCap->sub_max_height = curInfo->subpicture_max_height;
curCap->flags = curInfo->flags;
msg_Dbg (p_vout, "surface type %d: Max size: %d %d.",
i, curCap->max_width, curCap->max_height);
msg_Dbg (p_vout, "surface subtype %d: Max subpic size: %d %d.",
i, curCap->sub_max_width, curCap->sub_max_height);
curCap->type_id = curInfo->surface_type_id;
formatValues = XvMCListSubpictureTypes( p_vout->p_sys->p_display,
i_xvport,
curCap->type_id,
&numSub );
curCap->subPicType.id = 0;
if( formatValues )
{
msg_Dbg( p_vout, "surface type %d: found %d XvMC subpicture types",
i, numSub);
for( j = 0; j<numSub; ++j )
{
if( formatValues[j].id == FOURCC_IA44 )
{
curCap->subPicType = formatValues[j];
msg_Dbg( p_vout,
"surface type %d: detected and using "
"IA44 subpicture type.", i );
/* Prefer IA44 */
break;
}
else if( formatValues[j].id == FOURCC_AI44 )
{
curCap->subPicType = formatValues[j];
msg_Dbg( p_vout,
"surface type %d: detected AI44 "
"subpicture type.", i );
}
}
}
XFree(formatValues);
curInfo++;
curCap++;
}
}
XFree(surfaceInfo);
/*
* Try to create a direct rendering context. This will fail if we are not
* on the displaying computer or an indirect context is not available.
*/
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
curCap = p_vout->p_sys->xvmc_cap;
if( Success == XvMCCreateContext( p_vout->p_sys->p_display, i_xvport,
curCap->type_id,
curCap->max_width,
curCap->max_height,
XVMC_DIRECT, &c) )
{
p_vout->p_sys->context_flags = XVMC_DIRECT;
}
else if( Success == XvMCCreateContext( p_vout->p_sys->p_display, i_xvport,
curCap->type_id,
curCap->max_width,
curCap->max_height,
0, &c) )
{
p_vout->p_sys->context_flags = 0;
}
else
{
if( p_vout->p_sys->xvmc_cap )
free( p_vout->p_sys->xvmc_cap );
p_vout->p_sys->xvmc_cap = NULL;
msg_Err( p_vout, "use of direct XvMC context on a remote display failed"
" falling back to XV." );
xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
return VLC_SUCCESS;
}
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
XvMCDestroyContext( p_vout->p_sys->p_display, &c );
xxmc_xvmc_surface_handler_construct(p_vout );
/* p_vout->p_sys->capabilities |= VO_CAP_XXMC; */
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
init_xx44_palette( &p_vout->p_sys->palette , 0 );
p_vout->p_sys->last_accel_request = 0xFFFFFFFF;
xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock );
return VLC_SUCCESS;
}
static int xxmc_setup_subpictures( vout_thread_t *p_vout,
unsigned int width, unsigned int height )
{
xvmc_capabilities_t *curCap = NULL;
XvMCSubpicture *sp = NULL;
if( p_vout->p_sys->contextActive )
{
curCap = p_vout->p_sys->xvmc_cap + p_vout->p_sys->xvmc_cur_cap;
if( (width > curCap->sub_max_width) ||
(height > curCap->sub_max_height) )
return VLC_EGENERIC;
if( (p_vout->p_sys->xvmc_backend_subpic =
(curCap->flags & XVMC_BACKEND_SUBPICTURE)) )
msg_Dbg( p_vout, "using backend subpictures." );
if (!p_vout->p_sys->subImage)
{
XLockDisplay( p_vout->p_sys->p_display );
msg_Dbg(p_vout, "xxmc_setup_subpictures");
#ifdef HAVE_SYS_SHM_H
if( p_vout->p_sys->b_shm )
{
/* Create image using XShm extension */
p_vout->p_sys->subImage = CreateShmImage( p_vout,
p_vout->p_sys->p_display,
p_vout->p_sys->i_xvport,
curCap->subPicType.id,
/* VLC2X11_FOURCC( p_vout->output. i_chroma ), */
&p_vout->p_sys->subShmInfo,
p_vout->output.i_width,
p_vout->output.i_height );
}
#endif /* HAVE_SYS_SHM_H */
XUnlockDisplay( p_vout->p_sys->p_display );
if( !p_vout->p_sys->subImage )
{
msg_Dbg(p_vout, "failed allocating XvImage for supbictures" );
return VLC_EGENERIC;
}
}
sp = xxmc_xvmc_alloc_subpicture( p_vout, &p_vout->p_sys->context,
width, height,
curCap->subPicType.id );
if( !sp == NULL )
return VLC_EGENERIC;
init_xx44_palette( &p_vout->p_sys->palette, sp->num_palette_entries );
p_vout->p_sys->xvmc_palette = (char *) malloc( sp->num_palette_entries
* sp->entry_bytes );
xxmc_xvmc_free_subpicture( p_vout, sp);
if( !p_vout->p_sys->xvmc_pallette )
return VLC_EGENERIC;
p_vout->p_sys->hwSubpictures = 1;
}
return VLC_SUCCESS;
}
static void xvmc_check_colorkey_properties( vout_thread_t *p_vout )
{
int num,i;
XvAttribute *xvmc_attributes = NULL;
Atom ap;
/*
* Determine if the context is of "Overlay" type. If so,
* check whether we can autopaint.
*/
p_vout->p_sys->have_xvmc_autopaint = 0;
if( p_vout->p_sys->context_flags & XVMC_OVERLAID_SURFACE )
{
msg_Dbg( p_vout, "check colorkey properties" );
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
xvmc_attributes = XvMCQueryAttributes( p_vout->p_sys->p_display,
&p_vout->p_sys->context,
&num );
if( xvmc_attributes )
{
for( i = 0; i < num; ++i )
{
if( strncmp( "XV_AUTOPAINT_COLORKEY",
xvmc_attributes[i].name,
21) == 0)
{
ap = XInternAtom( p_vout->p_sys->p_display,
"XV_AUTOPAINT_COLORKEY",
False );
XvMCSetAttribute( p_vout->p_sys->p_display,
&p_vout->p_sys->context,
ap,
1 ); /* p_vout->p_sys->props[VO_PROP_AUTOPAINT_COLORKEY].value */
p_vout->p_sys->have_xvmc_autopaint = 1;
msg_Dbg( p_vout, "has xvmc autopaint" );
}
}
}
XFree( xvmc_attributes );
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
/* p_vout->p_sys->xvmc_xoverlay_type = X11OSD_COLORKEY; */
}
#if 0
else
{
p_vout->p_sys->xvmc_xoverlay_type = X11OSD_SHAPED;
}
#endif
}
static void xxmc_xvmc_destroy_surfaces( vout_thread_t *p_vout )
{
int i;
xvmc_surface_handler_t *handler = NULL;
handler = &p_vout->p_sys->xvmc_surf_handler;
pthread_mutex_lock( &handler->mutex );
for( i = 0; i < XVMC_MAX_SURFACES; ++i )
{
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
if( handler->surfValid[i] )
{
XvMCFlushSurface( p_vout->p_sys->p_display , handler->surfaces+i);
XvMCSyncSurface( p_vout->p_sys->p_display, handler->surfaces+i );
XvMCHideSurface( p_vout->p_sys->p_display, handler->surfaces+i );
XvMCDestroySurface( p_vout->p_sys->p_display, handler->surfaces+i );
}
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
handler->surfValid[i] = 0;
}
pthread_mutex_unlock( &handler->mutex );
}
static void xxmc_xvmc_destroy_subpictures( vout_thread_t *p_vout )
{
int i;
xvmc_surface_handler_t *handler = NULL;
handler = &p_vout->p_sys->xvmc_surf_handler;
pthread_mutex_lock( &handler->mutex );
for( i = 0; i < XVMC_MAX_SUBPICTURES; ++i )
{
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
if( handler->subValid[i] )
{
XvMCFlushSubpicture( p_vout->p_sys->p_display , handler->subpictures+i);
XvMCSyncSubpicture( p_vout->p_sys->p_display, handler->subpictures+i );
XvMCDestroySubpicture( p_vout->p_sys->p_display, handler->subpictures+i );
}
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
handler->subValid[i] = 0;
}
pthread_mutex_unlock( &handler->mutex );
}
static XvMCSurface *xxmc_xvmc_alloc_surface( vout_thread_t *p_vout,
XvMCContext *context )
{
xvmc_surface_handler_t *handler = NULL;
int i;
handler = &p_vout->p_sys->xvmc_surf_handler;
pthread_mutex_lock( &handler->mutex );
xxmc_xvmc_dump_surfaces( p_vout );
for( i = 0; i < XVMC_MAX_SURFACES; ++i )
{
if( handler->surfValid[i] && !handler->surfInUse[i] )
{
handler->surfInUse[i] = 1;
xxmc_xvmc_dump_surfaces( p_vout );
pthread_mutex_unlock( &handler->mutex );
return (handler->surfaces + i);
}
}
for( i = 0; i < XVMC_MAX_SURFACES; ++i )
{
if( !handler->surfInUse[i] )
{
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
if( Success != XvMCCreateSurface( p_vout->p_sys->p_display
context,
handler->surfaces + i) )
{
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
pthread_mutex_unlock( &handler->mutex );
return NULL;
}
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
msg_Dbg( p_vout, "created surface %d", i );
handler->surfInUse[i] = 1;
handler->surfValid[i] = 1;
pthread_mutex_unlock( &handler->mutex );
return (handler->surfaces + i);
}
}
pthread_mutex_unlock( &handler->mutex );
return NULL;
}
void xxmc_dispose_context( vout_thread_t *p_vout )
{
if( p_vout->p_sys->contextActive )
{
if( p_vout->p_sys->xvmc_accel &
(VLC_XVMC_ACCEL_MOCOMP | VLC_XVMC_ACCEL_IDCT) )
{
xvmc_macroblocks_t *macroblocks = NULL;
macroblocks = &p_vout->p_sys->macroblocks;
XvMCDestroyMacroBlocks( p_vout->p_sys->p_display,
&macroblocks->macro_blocks );
XvMCDestroyBlocks( p_vout->p_sys->p_display,
&macroblocks->blocks );
}
msg_Dbg( p_vout, "freeing up XvMC surfaces and subpictures" );
if( p_vout->p_sys->xvmc_palette )
free( p_vout->p_sys->xvmc_palette );
dispose_xx44_palette( &p_vout->p_sys->palette );
xxmc_xvmc_destroy_subpictures( p_vout );
xxmc_xvmc_destroy_surfaces( p_vout );
msg_Dbg(p_vout, "freeing up XvMC Context.");
XLockDisplay( p_vout->p_sys->p_display );
if( p_vout->p_sys->subImage )
{
XFree( p_vout->p_sys->subImage );
p_vout->p_sys->subImage = NULL;
}
p_vout->p_sys->subImage = NULL;
XUnlockDisplay( p_vout->p_sys->p_display );
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
XvMCDestroyContext( p_vout->p_sys->p_display,
&p_vout->p_sys->context );
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
p_vout->p_sys->contextActive = 0;
p_vout->p_sys->hwSubpictures = 0;
p_vout->p_sys->xvmc_accel = 0;
}
}
static int xxmc_find_context( vout_thread_t *p_vout, vlc_xxmc_t *xxmc,
unsigned int width, unsigned int height )
{
int i, k;
vlc_bool_t found = VLC_FALSE;
xvmc_capabilities_t *curCap = NULL;
unsigned int request_mpeg_flags, request_accel_flags;
request_mpeg_flags = xxmc->mpeg;
for( k = 0; k < NUM_ACCEL_PRIORITY; ++k )
{
request_accel_flags = xxmc->acceleration & accel_priority[k];
if( !request_accel_flags )
continue;
curCap = p_vout->p_sys->xvmc_cap;
for( i =0; i < p_vout->p_sys->xvmc_num_cap; ++i )
{
msg_Dbg( p_vout, "surface type %d, capabilities 0x%8x 0x%8x",
i,
curCap->mpeg_flags,
curCap->accel_flags );
msg_Dbg( p_vout, "fequests: 0x%8x 0x%8x",
request_mpeg_flags,
request_accel_flags );
if( ( (curCap->mpeg_flags & request_mpeg_flags) == request_mpeg_flags) &&
(curCap->accel_flags & request_accel_flags) &&
(width <= curCap->max_width) &&
(height <= curCap->max_height) )
{
found = VLC_TRUE;
break;
}
curCap++;
}
if( found )
{
p_vout->p_sys->xvmc_cur_cap = i;
break;
}
}
if( found )
{
p_vout->p_sys->xvmc_accel = request_accel_flags;
p_vout->p_sys->unsigned_intra = (curCap->flags & XVMC_INTRA_UNSIGNED);
return 1;
}
p_vout->p_sys->xvmc_accel = 0;
return 0;
}
static int xxmc_create_context( vout_thread_t *p_vout,
unsigned int width, unsigned int height )
{
xvmc_capabilities_t *curCap = NULL;
curCap = p_vout->p_sys->xvmc_cap + p_vout->p_sys->xvmc_cur_cap;
msg_Dbg( p_vout, "creating new XvMC context %d", curCap->type_id );
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
if( Success == XvMCCreateContext( p_vout->p_sys->p_display,
p_vout->p_sys->i_xvport,
curCap->type_id,
width,
height,
p_vout->p_sys->context_flags,
&p_vout->p_sys->context ) )
{
p_vout->p_sys->xvmc_mpeg = curCap->mpeg_flags;
p_vout->p_sys->xvmc_width = width;
p_vout->p_sys->xvmc_height = height;
p_vout->p_sys->contextActive = 1;
}
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
return p_vout->p_sys->contextActive;
}
static void xvmc_flushsync(picture_t *picture)
{
vout_thread_t *p_vout = picture->p_sys->p_vout;
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
if( ! xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf)) {
msg_Dbg(p_vout, "xvmc_flushsync 1 : %d", picture->p_sys->xxmc_data.result );
picture->p_sys->xxmc_data.result = 128;
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
return;
}
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
picture->p_sys->xxmc_data.result =
XvMCFlushSurface( p_vout->p_sys->p_display,
picture->p_sys->xvmc_surf );
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
}
static void xvmc_flush(picture_t *picture)
{
vout_thread_t *p_vout = picture->p_sys->p_vout;
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
if ( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
{
msg_Dbg(p_vout, "xvmc flush 1 : %d", picture->p_sys->xxmc_data.result );
picture->p_sys->xxmc_data.result = 128;
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
return;
}
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
picture->p_sys->xxmc_data.result =
XvMCFlushSurface( p_vout->p_sys->p_display,
picture->p_sys->xvmc_surf );
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
}
static int xxmc_frame_updates( vout_thread_t *p_vout, picture_t *picture )
{
vlc_xxmc_t *xxmc = &picture->p_sys->xxmc_data;
/*
* If we have changed context since the surface was updated, xvmc_surf
* is either NULL or invalid. If it is invalid. Set it to NULL.
* Also if there are other users of this surface, deregister our use of
* it and later try to allocate a new, fresh one.
*/
if( picture->p_sys->xvmc_surf )
{
if( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
{
xxmc_xvmc_free_surface( p_vout , picture->p_sys->xvmc_surf );
picture->p_sys->xvmc_surf = NULL;
}
}
#if 0
if( picture->p_sys->p_image )
{
memset( picture->p_sys->p_image->data, 0,
picture->p_sys->p_image->width
* picture->p_sys->p_image->height );
}
#endif
/*
* If it is NULL create a new surface.
*/
if( !picture->p_sys->xvmc_surf )
{
picture->p_sys->xvmc_surf = xxmc_xvmc_alloc_surface( p_vout,
&p_vout->p_sys->context );
if( !picture->p_sys->xvmc_surf )
{
msg_Err( p_vout, "accelerated surface allocation failed.\n"
" You are probably out of framebuffer memory.\n"
" Falling back to software decoding." );
p_vout->p_sys->xvmc_accel = 0;
xxmc_dispose_context( p_vout );
return VLC_EGENERIC;
}
}
xxmc->acceleration = p_vout->p_sys->xvmc_accel;
xxmc->proc_xxmc_flush = xvmc_flush;
xxmc->proc_xxmc_flushsync = xvmc_flushsync;
xxmc->xvmc.proc_macro_block = NULL;
#if 0
frame->vo_frame.proc_duplicate_frame_data = xxmc_duplicate_frame_data;
#endif
xxmc->proc_xxmc_begin = xvmc_vld_frame;
xxmc->proc_xxmc_slice = xvmc_vld_slice;
return VLC_SUCCESS;
}
static int xxmc_xvmc_update_context( vout_thread_t *p_vout,
picture_t *picture, uint32_t width, uint32_t height )
{
vlc_xxmc_t *xxmc = &picture->p_sys->xxmc_data;
/*
* Are we at all capable of doing XvMC ?
*/
if( p_vout->p_sys->xvmc_cap == 0 )
return VLC_EGENERIC;
msg_Dbg( p_vout, "new format: need to change XvMC context. "
"width: %d height: %d mpeg: %d acceleration: %d",
width, height,
xxmc->mpeg, xxmc->acceleration );
if( picture->p_sys->xvmc_surf )
xxmc_xvmc_free_surface( p_vout , picture->p_sys->xvmc_surf );
picture->p_sys->xvmc_surf = NULL;
xxmc_dispose_context( p_vout );
if( xxmc_find_context( p_vout, xxmc, width, height ) )
{
xxmc_create_context( p_vout, width, height);
xvmc_check_colorkey_properties( p_vout );
xxmc_setup_subpictures(p_vout, width, height);
}
if( !p_vout->p_sys->contextActive )
{
msg_Dbg( p_vout, "using software decoding for this stream" );
p_vout->p_sys->xvmc_accel = 0;
}
else
{
msg_Dbg(p_vout, "using hardware decoding for this stream." );
}
p_vout->p_sys->xvmc_mpeg = xxmc->mpeg;
p_vout->p_sys->xvmc_width = width;
p_vout->p_sys->xvmc_height = height;
return p_vout->p_sys->contextActive;
}
void xxmc_do_update_frame( picture_t *picture, uint32_t width, uint32_t height,
double ratio, int format, int flags)
{
vout_thread_t *p_vout = picture->p_sys->p_vout;
int indextime = 0;
int status = 0;
picture->p_sys->xxmc_data.decoded = 0;
picture->p_sys->nb_display = 0;
picture->b_force = 0;
vlc_xxmc_t *xxmc = &picture->p_sys->xxmc_data;
xvmc_context_writer_lock( &p_vout->p_sys->xvmc_lock);
if( (p_vout->p_sys->last_accel_request != xxmc->acceleration) ||
(p_vout->p_sys->xvmc_mpeg != xxmc->mpeg) ||
(p_vout->p_sys->xvmc_width != width) ||
(p_vout->p_sys->xvmc_height != height))
{
p_vout->p_sys->last_accel_request = xxmc->acceleration;
xxmc_xvmc_update_context( p_vout, picture, width, height );
}
if( p_vout->p_sys->contextActive )
xxmc_frame_updates( p_vout, picture );
if( !p_vout->p_sys->contextActive )
{
xxmc->acceleration = 0;
xxmc->xvmc.macroblocks = 0;
}
else
{
picture->format.i_chroma = format;
}
xvmc_context_writer_unlock( &p_vout->p_sys->xvmc_lock);
XvMCGetSurfaceStatus( p_vout->p_sys->p_display,
picture->p_sys->xvmc_surf,
&status );
/* Wait a little till frame is being displayed */
while( status & XVMC_DISPLAYING )
{
msleep(1);
XvMCGetSurfaceStatus( p_vout->p_sys->p_display,
picture->p_sys->xvmc_surf,
&status );
indextime++;
if( indextime > 4 )
break;
}
}
#if 0
/* called xlocked */
static void dispose_ximage( vout_thread_t *p_vout, XShmSegmentInfo *shminfo,
XvImage *myimage )
{
# ifdef HAVE_SYS_SHM_H
if( p_vout->p_sys->b_shm )
{
XShmDetach( p_vout->p_sys->p_display, shminfo );
XFree( myimage );
shmdt( shminfo->shmaddr );
if( shminfo->shmid >= 0 )
{
shmctl( shminfo->shmid, IPC_RMID, 0 );
shminfo->shmid = -1;
}
}
else
#endif
{
if( myimage->data )
free(myimage->data);
XFree (myimage);
}
}
#endif
void xvmc_vld_frame( picture_t *picture )
{
vout_sys_t *p_sys = picture->p_sys;
vout_thread_t *p_vout = p_sys->p_vout;
vlc_vld_frame_t *vft = &(p_sys->xxmc_data.vld_frame);
picture_t *ff = (picture_t *) vft->forward_reference_picture;
picture_t *bf = (picture_t *) vft->backward_reference_picture;
XvMCMpegControl ctl;
XvMCSurface *fs=0, *bs=0;
XvMCQMatrix qmx;
ctl.BHMV_range = vft->mv_ranges[0][0];
ctl.BVMV_range = vft->mv_ranges[0][1];
ctl.FHMV_range = vft->mv_ranges[1][0];
ctl.FVMV_range = vft->mv_ranges[1][1];
ctl.picture_structure = vft->picture_structure;
ctl.intra_dc_precision = vft->intra_dc_precision;
ctl.picture_coding_type = vft->picture_coding_type;
ctl.mpeg_coding = (vft->mpeg_coding == 0) ? XVMC_MPEG_1 : XVMC_MPEG_2;
ctl.flags = 0;
ctl.flags |= (vft->progressive_sequence) ? XVMC_PROGRESSIVE_SEQUENCE : 0;
ctl.flags |= (vft->scan) ? XVMC_ALTERNATE_SCAN : XVMC_ZIG_ZAG_SCAN;
ctl.flags |= (vft->pred_dct_frame) ?
XVMC_PRED_DCT_FRAME : XVMC_PRED_DCT_FIELD;
ctl.flags |= (picture->b_top_field_first) ?
XVMC_TOP_FIELD_FIRST : XVMC_BOTTOM_FIELD_FIRST;
ctl.flags |= (vft->concealment_motion_vectors) ?
XVMC_CONCEALMENT_MOTION_VECTORS : 0;
ctl.flags |= (vft->q_scale_type) ? XVMC_Q_SCALE_TYPE : 0;
ctl.flags |= (vft->intra_vlc_format) ? XVMC_INTRA_VLC_FORMAT : 0;
ctl.flags |= (vft->second_field) ? XVMC_SECOND_FIELD : 0;
if( ff )
fs = ff->p_sys->xvmc_surf;
if( bf )
bs = bf->p_sys->xvmc_surf;
/*
* Below is for interlaced streams and second_field.
*/
if( ctl.picture_coding_type == P_TYPE ) /* XVMC_P_PICTURE) */
bs = picture->p_sys->xvmc_surf;
if( (qmx.load_intra_quantiser_matrix = vft->load_intra_quantizer_matrix) )
{
memcpy( qmx.intra_quantiser_matrix, vft->intra_quantizer_matrix,
sizeof(qmx.intra_quantiser_matrix) );
}
if( (qmx.load_non_intra_quantiser_matrix =
vft->load_non_intra_quantizer_matrix) )
{
memcpy( qmx.non_intra_quantiser_matrix, vft->non_intra_quantizer_matrix,
sizeof(qmx.non_intra_quantiser_matrix) );
}
qmx.load_chroma_intra_quantiser_matrix = 0;
qmx.load_chroma_non_intra_quantiser_matrix = 0;
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
if( ! xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf) )
{
picture->p_sys->xxmc_data.result = 128;
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
return;
}
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
XvMCLoadQMatrix( p_vout->p_sys->p_display, &p_vout->p_sys->context, &qmx );
do {
picture->p_sys->xxmc_data.result =
XvMCBeginSurface( p_vout->p_sys->p_display,
&p_vout->p_sys->context,
picture->p_sys->xvmc_surf,
fs, bs, &ctl );
} while( !picture->p_sys->xxmc_data.result );
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
}
void xvmc_vld_slice( picture_t *picture )
{
vout_sys_t *p_sys = picture->p_sys;
vout_thread_t *p_vout = p_sys->p_vout;
xvmc_context_reader_lock( &p_vout->p_sys->xvmc_lock );
if( !xxmc_xvmc_surface_valid( p_vout, picture->p_sys->xvmc_surf ) )
{
picture->p_sys->xxmc_data.result = 128;
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
msg_Err(p_vout, "vld slice error" );
return;
}
XVMCLOCKDISPLAY( p_vout->p_sys->p_display );
picture->p_sys->xxmc_data.result =
XvMCPutSlice2( p_vout->p_sys->p_display,
&p_vout->p_sys->context,
picture->p_sys->xxmc_data.slice_data,
picture->p_sys->xxmc_data.slice_data_size,
picture->p_sys->xxmc_data.slice_code );
if( picture->p_sys->xxmc_data.result != 0 )
msg_Err( p_vout, "vlc slice error %d",
picture->p_sys->xxmc_data.result );
/*
* If CPU-saving mode is enabled, sleep after every xxmc->sleep slice. This will free
* up the cpu while the decoder is working on the slice. The value of xxmc->sleep is calculated
* so that the decoder thread sleeps at most 50% of the frame delay,
* assuming a 2.6 kernel clock of 1000 Hz.
*/
XVMCUNLOCKDISPLAY( p_vout->p_sys->p_display );
xvmc_context_reader_unlock( &p_vout->p_sys->xvmc_lock );
#if 0
if( p_vout->p_sys->cpu_save_enabled )
{
p_vout->p_sys->cpu_saver += 1.;
if( p_vout->p_sys->cpu_saver >= picture->p_sys->xxmc_data.sleep )
{
usleep(1);
p_vout->p_sys->cpu_saver -= picture->p_sys->xxmc_data.sleep;
}
}
#endif
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment