RFC: Get rid of mpegplayer plugin
It might have made sense once upon a time, but in today's world... Change-Id: I5d638e6f7a2308c50ab12bd901338f02cf426aae
This commit is contained in:
parent
9ce5b2a2ed
commit
d25d24812e
60 changed files with 5 additions and 21189 deletions
|
@ -14263,128 +14263,9 @@
|
|||
*: "View Played Games"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_MENU_AUDIO_OPTIONS
|
||||
desc: in mpegplayer menus
|
||||
user: core
|
||||
<source>
|
||||
*: "Audio Options"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Audio Options"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Audio Options"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_MENU_RESUME_OPTIONS
|
||||
desc: in mpegplayer menus
|
||||
user: core
|
||||
<source>
|
||||
*: "Resume Options"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Resume Options"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Resume Options"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_MENU_PLAY_MODE
|
||||
desc: in mpegplayer menus
|
||||
user: core
|
||||
<source>
|
||||
*: "Play Mode"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Play Mode"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Play Mode"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_SINGLE
|
||||
desc: in mpegplayer menus
|
||||
user: core
|
||||
<source>
|
||||
*: "Single"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Single"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Single"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_USE_SOUND_SETTING
|
||||
desc: in mpegplayer menus
|
||||
user: core
|
||||
<source>
|
||||
*: "Use sound setting"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Use sound setting"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Use sound setting"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_RESTART_PLAYBACK
|
||||
desc: in the mpegplayer settings menu
|
||||
user: core
|
||||
<source>
|
||||
*: "Play from beginning"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Play from beginning"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Play from beginning"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_SET_RESUME_TIME
|
||||
desc: in the mpegplayer settings menu
|
||||
user: core
|
||||
<source>
|
||||
*: "Set resume time (min)"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Set resume time (min)"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Set resume time"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_DISPLAY_FPS
|
||||
desc: in the mpegplayer and pictureflow settings menus
|
||||
desc: in the pictureflow settings menus
|
||||
user: core
|
||||
<source>
|
||||
*: "Display FPS"
|
||||
|
@ -14396,176 +14277,6 @@
|
|||
*: "Display FPS"
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_LIMIT_FPS
|
||||
desc: in the mpegplayer settings menu
|
||||
user: core
|
||||
<source>
|
||||
*: "Limit FPS"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Limit FPS"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Limit FPS"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_SKIP_FRAMES
|
||||
desc: in the mpegplayer settings menu
|
||||
user: core
|
||||
<source>
|
||||
*: "Skip frames"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Skip frames"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Skip frames"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_BACKLIGHT_BRIGHTNESS
|
||||
desc: in the mpegplayer settings menu
|
||||
user: core
|
||||
<source>
|
||||
*: "Backlight brightness"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Backlight brightness"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Backlight brightness"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_USE_COMMON_SETTING
|
||||
desc: in the mpegplayer settings menu
|
||||
user: core
|
||||
<source>
|
||||
*: "Use common setting"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Use common setting"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Use common setting"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_TONE_CONTROLS
|
||||
desc: in the mpegplayer settings menu
|
||||
user: core
|
||||
<source>
|
||||
*: "Tone controls"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Tone controls"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Tone controls"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_FORCE_START_MENU
|
||||
desc: in mpegplayer menus
|
||||
user: core
|
||||
<source>
|
||||
*: "Start menu"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Start menu"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Start menu"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_CONDITIONAL_START_MENU
|
||||
desc: in mpegplayer menus
|
||||
user: core
|
||||
<source>
|
||||
*: "Start menu if not completed"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Start menu if not completed"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Start menu if not completed"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_AUTO_RESUME
|
||||
desc: in mpegplayer menus
|
||||
user: core
|
||||
<source>
|
||||
*: "Resume automatically"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Resume automatically"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Resume automatically"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_CLEAR_ALL_RESUMES
|
||||
desc: in the mpegplayer settings menu
|
||||
user: core
|
||||
<source>
|
||||
*: "Clear all resumes"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Clear all resumes"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Clear all resumes"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_UNAVAILABLE
|
||||
desc: in mpegplayer settings
|
||||
user: core
|
||||
<source>
|
||||
*: "Unavailable"
|
||||
lowmem: none
|
||||
</source>
|
||||
<dest>
|
||||
*: "Unavailable"
|
||||
lowmem: none
|
||||
</dest>
|
||||
<voice>
|
||||
*: "Unavailable"
|
||||
lowmem: none
|
||||
</voice>
|
||||
</phrase>
|
||||
<phrase>
|
||||
id: LANG_TOGGLE_ITEM
|
||||
desc: in main_menu_config
|
||||
|
|
|
@ -68,7 +68,6 @@ mikmod,viewers
|
|||
minesweeper,games
|
||||
mosaique,demos
|
||||
mp3_encoder,apps
|
||||
mpegplayer,viewers
|
||||
multiboot_select,apps
|
||||
nim,games
|
||||
open_plugins,viewers
|
||||
|
|
|
@ -78,10 +78,6 @@ mikmod
|
|||
pdbox
|
||||
#endif
|
||||
|
||||
#if !defined(RB_PROFILE) && MEMORYSIZE > 2 /* mpegplayer allocates at least 2MB of RAM */
|
||||
mpegplayer
|
||||
#endif
|
||||
|
||||
/* Lua needs at least 160 KB to work in */
|
||||
#if PLUGIN_BUFFER_SIZE >= 0x80000
|
||||
lua
|
||||
|
|
|
@ -49,11 +49,6 @@ invadrox_fire.6x6x1.bmp
|
|||
#endif
|
||||
#endif
|
||||
|
||||
/* MPEGplayer */
|
||||
mpegplayer_status_icons_8x8x1.bmp
|
||||
mpegplayer_status_icons_12x12x1.bmp
|
||||
mpegplayer_status_icons_16x16x1.bmp
|
||||
|
||||
#if LCD_WIDTH == 160 && LCD_HEIGHT == 128 && LCD_DEPTH < 16
|
||||
superdom_boarditems.160x128x1.bmp
|
||||
#endif
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 158 B |
Binary file not shown.
Before Width: | Height: | Size: 254 B |
Binary file not shown.
Before Width: | Height: | Size: 126 B |
|
@ -1,35 +0,0 @@
|
|||
libmpeg2/decode.c
|
||||
libmpeg2/header.c
|
||||
libmpeg2/idct.c
|
||||
libmpeg2/motion_comp.c
|
||||
libmpeg2/slice.c
|
||||
|
||||
#ifdef CPU_COLDFIRE
|
||||
libmpeg2/idct_coldfire.S
|
||||
libmpeg2/motion_comp_coldfire_c.c
|
||||
libmpeg2/motion_comp_coldfire_s.S
|
||||
#elif defined CPU_ARM
|
||||
#if ARM_ARCH >= 6
|
||||
libmpeg2/idct_armv6.S
|
||||
#else
|
||||
libmpeg2/idct_arm.S
|
||||
#endif
|
||||
libmpeg2/motion_comp_arm_c.c
|
||||
libmpeg2/motion_comp_arm_s.S
|
||||
#else /* other CPU or SIM */
|
||||
libmpeg2/motion_comp_c.c
|
||||
#endif /* CPU_* */
|
||||
|
||||
|
||||
|
||||
alloc.c
|
||||
video_out_rockbox.c
|
||||
video_thread.c
|
||||
pcm_output.c
|
||||
audio_thread.c
|
||||
disk_buf.c
|
||||
mpeg_settings.c
|
||||
stream_mgr.c
|
||||
mpegplayer.c
|
||||
mpeg_parser.c
|
||||
mpeg_misc.c
|
|
@ -1,233 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* $Id$
|
||||
* libmpeg2 sync history:
|
||||
* 2008-07-01 - CVS revision 1.13
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "mpegplayer.h"
|
||||
#include <system.h>
|
||||
|
||||
/* Main allocator */
|
||||
static off_t mem_ptr;
|
||||
static size_t bufsize;
|
||||
static unsigned char* mallocbuf;
|
||||
|
||||
/* libmpeg2 allocator */
|
||||
static off_t mpeg2_mem_ptr SHAREDBSS_ATTR;
|
||||
static size_t mpeg2_bufsize SHAREDBSS_ATTR;
|
||||
static unsigned char *mpeg2_mallocbuf SHAREDBSS_ATTR;
|
||||
static unsigned char *mpeg2_bufallocbuf SHAREDBSS_ATTR;
|
||||
|
||||
#if defined(DEBUG) || defined(SIMULATOR)
|
||||
const char * mpeg_get_reason_str(int reason)
|
||||
{
|
||||
const char *str;
|
||||
|
||||
switch (reason)
|
||||
{
|
||||
case MPEG2_ALLOC_MPEG2DEC:
|
||||
str = "MPEG2_ALLOC_MPEG2DEC";
|
||||
break;
|
||||
case MPEG2_ALLOC_CHUNK:
|
||||
str = "MPEG2_ALLOC_CHUNK";
|
||||
break;
|
||||
case MPEG2_ALLOC_YUV:
|
||||
str = "MPEG2_ALLOC_YUV";
|
||||
break;
|
||||
case MPEG2_ALLOC_CONVERT_ID:
|
||||
str = "MPEG2_ALLOC_CONVERT_ID";
|
||||
break;
|
||||
case MPEG2_ALLOC_CONVERTED:
|
||||
str = "MPEG2_ALLOC_CONVERTED";
|
||||
break;
|
||||
case MPEG_ALLOC_MPEG2_BUFFER:
|
||||
str = "MPEG_ALLOC_MPEG2_BUFFER";
|
||||
break;
|
||||
case MPEG_ALLOC_AUDIOBUF:
|
||||
str = "MPEG_ALLOC_AUDIOBUF";
|
||||
break;
|
||||
case MPEG_ALLOC_PCMOUT:
|
||||
str = "MPEG_ALLOC_PCMOUT";
|
||||
break;
|
||||
case MPEG_ALLOC_DISKBUF:
|
||||
str = "MPEG_ALLOC_DISKBUF";
|
||||
break;
|
||||
case MPEG_ALLOC_CODEC_MALLOC:
|
||||
str = "MPEG_ALLOC_CODEC_MALLOC";
|
||||
break;
|
||||
case MPEG_ALLOC_CODEC_CALLOC:
|
||||
str = "MPEG_ALLOC_CODEC_CALLOC";
|
||||
break;
|
||||
default:
|
||||
str = "Unknown";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void * mpeg_malloc_internal (unsigned char *mallocbuf,
|
||||
off_t *mem_ptr,
|
||||
size_t bufsize,
|
||||
unsigned size,
|
||||
int reason)
|
||||
{
|
||||
void *x;
|
||||
|
||||
DEBUGF("mpeg_alloc_internal: bs:%lu s:%u reason:%s (%d)\n",
|
||||
(unsigned long)bufsize, size, mpeg_get_reason_str(reason), reason);
|
||||
|
||||
if ((size_t) (*mem_ptr + size) > bufsize)
|
||||
{
|
||||
DEBUGF("OUT OF MEMORY\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x = &mallocbuf[*mem_ptr];
|
||||
*mem_ptr += (size + 3) & ~3; /* Keep memory 32-bit aligned */
|
||||
|
||||
return x;
|
||||
(void)reason;
|
||||
}
|
||||
|
||||
void *mpeg_malloc(size_t size, mpeg2_alloc_t reason)
|
||||
{
|
||||
return mpeg_malloc_internal(mallocbuf, &mem_ptr, bufsize, size,
|
||||
reason);
|
||||
}
|
||||
|
||||
void *mpeg_malloc_all(size_t *size_out, mpeg2_alloc_t reason)
|
||||
{
|
||||
/* Can steal all but MIN_MEMMARGIN */
|
||||
if (bufsize - mem_ptr < MIN_MEMMARGIN)
|
||||
return NULL;
|
||||
|
||||
*size_out = bufsize - mem_ptr - MIN_MEMMARGIN;
|
||||
return mpeg_malloc(*size_out, reason);
|
||||
}
|
||||
|
||||
bool mpeg_alloc_init(unsigned char *buf, size_t mallocsize)
|
||||
{
|
||||
mem_ptr = 0;
|
||||
/* Cache-align buffer or 4-byte align */
|
||||
mallocbuf = buf;
|
||||
bufsize = mallocsize;
|
||||
ALIGN_BUFFER(mallocbuf, bufsize, CACHEALIGN_UP(4));
|
||||
|
||||
/* Separate allocator for video */
|
||||
mpeg2_mem_ptr = 0;
|
||||
mpeg2_mallocbuf = mallocbuf;
|
||||
mpeg2_bufallocbuf = mallocbuf;
|
||||
mpeg2_bufsize = CACHEALIGN_UP(LIBMPEG2_ALLOC_SIZE);
|
||||
|
||||
if (mpeg_malloc_internal(mallocbuf, &mem_ptr,
|
||||
bufsize, mpeg2_bufsize,
|
||||
MPEG_ALLOC_MPEG2_BUFFER) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IF_COP(rb->commit_discard_dcache());
|
||||
return true;
|
||||
}
|
||||
|
||||
/* allocate non-dedicated buffer space which mpeg2_mem_reset will free */
|
||||
void * mpeg2_malloc(unsigned size, mpeg2_alloc_t reason)
|
||||
{
|
||||
void *ptr = mpeg_malloc_internal(mpeg2_mallocbuf, &mpeg2_mem_ptr,
|
||||
mpeg2_bufsize, size, reason);
|
||||
/* libmpeg2 expects zero-initialized allocations */
|
||||
if (ptr)
|
||||
rb->memset(ptr, 0, size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* allocate dedicated buffer - memory behind buffer pointer becomes dedicated
|
||||
so order is important */
|
||||
void * mpeg2_bufalloc(unsigned size, mpeg2_alloc_t reason)
|
||||
{
|
||||
void *buf = mpeg2_malloc(size, reason);
|
||||
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
mpeg2_bufallocbuf = &mpeg2_mallocbuf[mpeg2_mem_ptr];
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* return unused buffer portion and size */
|
||||
void * mpeg2_get_buf(size_t *size)
|
||||
{
|
||||
if ((size_t)mpeg2_mem_ptr + 32 >= mpeg2_bufsize)
|
||||
return NULL;
|
||||
|
||||
*size = mpeg2_bufsize - mpeg2_mem_ptr;
|
||||
return &mpeg2_mallocbuf[mpeg2_mem_ptr];
|
||||
}
|
||||
|
||||
/* de-allocate all non-dedicated buffer space */
|
||||
void mpeg2_mem_reset(void)
|
||||
{
|
||||
DEBUGF("mpeg2_mem_reset\n");
|
||||
mpeg2_mem_ptr = mpeg2_bufallocbuf - mpeg2_mallocbuf;
|
||||
}
|
||||
|
||||
/* The following are expected by libmad */
|
||||
void * codec_malloc(size_t size)
|
||||
{
|
||||
void* ptr;
|
||||
|
||||
ptr = mpeg_malloc_internal(mallocbuf, &mem_ptr,
|
||||
bufsize, size, MPEG_ALLOC_CODEC_MALLOC);
|
||||
|
||||
if (ptr)
|
||||
rb->memset(ptr,0,size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void * codec_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void* ptr;
|
||||
|
||||
ptr = mpeg_malloc_internal(mallocbuf, &mem_ptr,
|
||||
bufsize, nmemb*size,
|
||||
MPEG_ALLOC_CODEC_CALLOC);
|
||||
|
||||
if (ptr)
|
||||
rb->memset(ptr,0,size);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void codec_free(void* ptr)
|
||||
{
|
||||
DEBUGF("codec_free - %p\n", ptr);
|
||||
#if 0
|
||||
mem_ptr = (void *)ptr - (void *)mallocbuf;
|
||||
#endif
|
||||
(void)ptr;
|
||||
}
|
|
@ -1,721 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* mpegplayer audio thread implementation
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "plugin.h"
|
||||
#include "mpegplayer.h"
|
||||
#include "codecs/libmad/bit.h"
|
||||
#include "codecs/libmad/mad.h"
|
||||
|
||||
/** Audio stream and thread **/
|
||||
struct pts_queue_slot;
|
||||
struct audio_thread_data
|
||||
{
|
||||
struct queue_event ev; /* Our event queue to receive commands */
|
||||
int state; /* Thread state */
|
||||
int status; /* Media status (STREAM_PLAYING, etc.) */
|
||||
int mad_errors; /* A count of the errors in each frame */
|
||||
unsigned samplerate; /* Current stream sample rate */
|
||||
int nchannels; /* Number of audio channels */
|
||||
struct dsp_config *dsp; /* The DSP we're using */
|
||||
struct dsp_buffer src; /* Current audio data for DSP processing */
|
||||
};
|
||||
|
||||
/* The audio thread is stolen from the core codec thread */
|
||||
static struct event_queue audio_str_queue SHAREDBSS_ATTR;
|
||||
static struct queue_sender_list audio_str_queue_send SHAREDBSS_ATTR;
|
||||
struct stream audio_str IBSS_ATTR;
|
||||
|
||||
/* libmad related definitions */
|
||||
static struct mad_stream stream IBSS_ATTR;
|
||||
static struct mad_frame frame IBSS_ATTR;
|
||||
static struct mad_synth synth IBSS_ATTR;
|
||||
|
||||
/*sbsample buffer for mad_frame*/
|
||||
mad_fixed_t sbsample[2][36][32];
|
||||
|
||||
/* 2567 bytes */
|
||||
static unsigned char mad_main_data[MAD_BUFFER_MDLEN];
|
||||
|
||||
/* There isn't enough room for this in IRAM on PortalPlayer, but there
|
||||
is for Coldfire. */
|
||||
|
||||
/* 4608 bytes */
|
||||
#if defined(CPU_COLDFIRE) || defined(CPU_S5L870X)
|
||||
static mad_fixed_t mad_frame_overlap[2][32][18] IBSS_ATTR;
|
||||
#else
|
||||
static mad_fixed_t mad_frame_overlap[2][32][18];
|
||||
#endif
|
||||
|
||||
/** A queue for saving needed information about MPEG audio packets **/
|
||||
#define AUDIODESC_QUEUE_LEN (1 << 5) /* 32 should be way more than sufficient -
|
||||
if not, the case is handled */
|
||||
#define AUDIODESC_QUEUE_MASK (AUDIODESC_QUEUE_LEN-1)
|
||||
struct audio_frame_desc
|
||||
{
|
||||
uint32_t time; /* Time stamp for packet in audio ticks */
|
||||
ssize_t size; /* Number of unprocessed bytes left in packet */
|
||||
};
|
||||
|
||||
/* This starts out wr == rd but will never be emptied to zero during
|
||||
streaming again in order to support initializing the first packet's
|
||||
timestamp without a special case */
|
||||
struct
|
||||
{
|
||||
/* Compressed audio data */
|
||||
uint8_t *start; /* Start of encoded audio buffer */
|
||||
uint8_t *ptr; /* Pointer to next encoded audio data */
|
||||
ssize_t used; /* Number of bytes in MPEG audio buffer */
|
||||
/* Compressed audio data descriptors */
|
||||
unsigned read, write;
|
||||
struct audio_frame_desc *curr; /* Current slot */
|
||||
struct audio_frame_desc descs[AUDIODESC_QUEUE_LEN];
|
||||
} audio_queue;
|
||||
|
||||
static inline int audiodesc_queue_count(void)
|
||||
{
|
||||
return audio_queue.write - audio_queue.read;
|
||||
}
|
||||
|
||||
static inline bool audiodesc_queue_full(void)
|
||||
{
|
||||
return audio_queue.used >= MPA_MAX_FRAME_SIZE + MAD_BUFFER_GUARD ||
|
||||
audiodesc_queue_count() >= AUDIODESC_QUEUE_LEN;
|
||||
}
|
||||
|
||||
/* Increments the queue tail postion - should be used to preincrement */
|
||||
static inline void audiodesc_queue_add_tail(void)
|
||||
{
|
||||
if (audiodesc_queue_full())
|
||||
{
|
||||
DEBUGF("audiodesc_queue_add_tail: audiodesc queue full!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
audio_queue.write++;
|
||||
}
|
||||
|
||||
/* Increments the queue head position - leaves one slot as current */
|
||||
static inline bool audiodesc_queue_remove_head(void)
|
||||
{
|
||||
if (audio_queue.write == audio_queue.read)
|
||||
return false;
|
||||
|
||||
audio_queue.read++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns the "tail" at the index just behind the write index */
|
||||
static inline struct audio_frame_desc * audiodesc_queue_tail(void)
|
||||
{
|
||||
return &audio_queue.descs[(audio_queue.write - 1) & AUDIODESC_QUEUE_MASK];
|
||||
}
|
||||
|
||||
/* Returns a pointer to the current head */
|
||||
static inline struct audio_frame_desc * audiodesc_queue_head(void)
|
||||
{
|
||||
return &audio_queue.descs[audio_queue.read & AUDIODESC_QUEUE_MASK];
|
||||
}
|
||||
|
||||
/* Resets the pts queue - call when starting and seeking */
|
||||
static void audio_queue_reset(void)
|
||||
{
|
||||
audio_queue.ptr = audio_queue.start;
|
||||
audio_queue.used = 0;
|
||||
audio_queue.read = 0;
|
||||
audio_queue.write = 0;
|
||||
rb->memset(audio_queue.descs, 0, sizeof (audio_queue.descs));
|
||||
audio_queue.curr = audiodesc_queue_head();
|
||||
}
|
||||
|
||||
static void audio_queue_advance_pos(ssize_t len)
|
||||
{
|
||||
audio_queue.ptr += len;
|
||||
audio_queue.used -= len;
|
||||
audio_queue.curr->size -= len;
|
||||
}
|
||||
|
||||
static int audio_buffer(struct stream *str, enum stream_parse_mode type)
|
||||
{
|
||||
int ret = STREAM_OK;
|
||||
|
||||
/* Carry any overshoot to the next size since we're technically
|
||||
-size bytes into it already. If size is negative an audio
|
||||
frame was split across packets. Old has to be saved before
|
||||
moving the head. */
|
||||
if (audio_queue.curr->size <= 0 && audiodesc_queue_remove_head())
|
||||
{
|
||||
struct audio_frame_desc *old = audio_queue.curr;
|
||||
audio_queue.curr = audiodesc_queue_head();
|
||||
audio_queue.curr->size += old->size;
|
||||
old->size = 0;
|
||||
}
|
||||
|
||||
/* Add packets to compressed audio buffer until it's full or the
|
||||
* timestamp queue is full - whichever happens first */
|
||||
while (!audiodesc_queue_full())
|
||||
{
|
||||
ret = parser_get_next_data(str, type);
|
||||
struct audio_frame_desc *curr;
|
||||
ssize_t len;
|
||||
|
||||
if (ret != STREAM_OK)
|
||||
break;
|
||||
|
||||
/* Get data from next audio packet */
|
||||
len = str->curr_packet_end - str->curr_packet;
|
||||
|
||||
if (str->pkt_flags & PKT_HAS_TS)
|
||||
{
|
||||
audiodesc_queue_add_tail();
|
||||
curr = audiodesc_queue_tail();
|
||||
curr->time = TS_TO_TICKS(str->pts);
|
||||
/* pts->size should have been zeroed when slot was
|
||||
freed */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Add to the one just behind the tail - this may be
|
||||
* the head or the previouly added tail - whether or
|
||||
* not we'll ever reach this is quite in question
|
||||
* since audio always seems to have every packet
|
||||
* timestamped */
|
||||
curr = audiodesc_queue_tail();
|
||||
}
|
||||
|
||||
curr->size += len;
|
||||
|
||||
/* Slide any remainder over to beginning */
|
||||
if (audio_queue.ptr > audio_queue.start && audio_queue.used > 0)
|
||||
{
|
||||
rb->memmove(audio_queue.start, audio_queue.ptr,
|
||||
audio_queue.used);
|
||||
}
|
||||
|
||||
/* Splice this packet onto any remainder */
|
||||
rb->memcpy(audio_queue.start + audio_queue.used,
|
||||
str->curr_packet, len);
|
||||
|
||||
audio_queue.used += len;
|
||||
audio_queue.ptr = audio_queue.start;
|
||||
|
||||
rb->yield();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialise libmad */
|
||||
static void init_mad(void)
|
||||
{
|
||||
/* init the sbsample buffer */
|
||||
frame.sbsample_prev = &sbsample;
|
||||
frame.sbsample = &sbsample;
|
||||
|
||||
/* We do this so libmad doesn't try to call codec_calloc(). This needs to
|
||||
* be called before mad_stream_init(), mad_frame_inti() and
|
||||
* mad_synth_init(). */
|
||||
frame.overlap = &mad_frame_overlap;
|
||||
stream.main_data = &mad_main_data;
|
||||
|
||||
/* Call mad initialization. Those will zero the arrays frame.overlap,
|
||||
* frame.sbsample and frame.sbsample_prev. Therefore there is no need to
|
||||
* zero them here. */
|
||||
mad_stream_init(&stream);
|
||||
mad_frame_init(&frame);
|
||||
mad_synth_init(&synth);
|
||||
}
|
||||
|
||||
/* Sync audio stream to a particular frame - see main decoder loop for
|
||||
* detailed remarks */
|
||||
static int audio_sync(struct audio_thread_data *td,
|
||||
struct str_sync_data *sd)
|
||||
{
|
||||
int retval = STREAM_MATCH;
|
||||
uint32_t sdtime = TS_TO_TICKS(clip_time(&audio_str, sd->time));
|
||||
uint32_t time;
|
||||
uint32_t duration = 0;
|
||||
struct stream *str;
|
||||
struct stream tmp_str;
|
||||
struct mad_header header;
|
||||
struct mad_stream stream;
|
||||
|
||||
if (td->ev.id == STREAM_SYNC)
|
||||
{
|
||||
/* Actually syncing for playback - use real stream */
|
||||
time = 0;
|
||||
str = &audio_str;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Probing - use temp stream */
|
||||
time = INVALID_TIMESTAMP;
|
||||
str = &tmp_str;
|
||||
str->id = audio_str.id;
|
||||
}
|
||||
|
||||
str->hdr.pos = sd->sk.pos;
|
||||
str->hdr.limit = sd->sk.pos + sd->sk.len;
|
||||
|
||||
mad_stream_init(&stream);
|
||||
mad_header_init(&header);
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (audio_buffer(str, STREAM_PM_RANDOM_ACCESS) == STREAM_DATA_END)
|
||||
{
|
||||
DEBUGF("audio_sync:STR_DATA_END\n aqu:%ld swl:%ld swr:%ld\n",
|
||||
(long)audio_queue.used, str->hdr.win_left, str->hdr.win_right);
|
||||
if (audio_queue.used <= MAD_BUFFER_GUARD)
|
||||
goto sync_data_end;
|
||||
}
|
||||
|
||||
stream.error = 0;
|
||||
mad_stream_buffer(&stream, audio_queue.ptr, audio_queue.used);
|
||||
|
||||
if (stream.sync && mad_stream_sync(&stream) < 0)
|
||||
{
|
||||
DEBUGF(" audio: mad_stream_sync failed\n");
|
||||
audio_queue_advance_pos(MAX(audio_queue.curr->size - 1, 1));
|
||||
continue;
|
||||
}
|
||||
|
||||
stream.sync = 0;
|
||||
|
||||
if (mad_header_decode(&header, &stream) < 0)
|
||||
{
|
||||
DEBUGF(" audio: mad_header_decode failed:%s\n",
|
||||
mad_stream_errorstr(&stream));
|
||||
audio_queue_advance_pos(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
duration = 32*MAD_NSBSAMPLES(&header);
|
||||
time = audio_queue.curr->time;
|
||||
|
||||
DEBUGF(" audio: ft:%u t:%u fe:%u nsamp:%u sampr:%u\n",
|
||||
(unsigned)TICKS_TO_TS(time), (unsigned)sd->time,
|
||||
(unsigned)TICKS_TO_TS(time + duration),
|
||||
(unsigned)duration, header.samplerate);
|
||||
|
||||
audio_queue_advance_pos(stream.this_frame - audio_queue.ptr);
|
||||
|
||||
if (time <= sdtime && sdtime < time + duration)
|
||||
{
|
||||
DEBUGF(" audio: ft<=t<fe\n");
|
||||
retval = STREAM_PERFECT_MATCH;
|
||||
break;
|
||||
}
|
||||
else if (time > sdtime)
|
||||
{
|
||||
DEBUGF(" audio: ft>t\n");
|
||||
break;
|
||||
}
|
||||
|
||||
audio_queue_advance_pos(stream.next_frame - audio_queue.ptr);
|
||||
audio_queue.curr->time += duration;
|
||||
|
||||
rb->yield();
|
||||
}
|
||||
|
||||
sync_data_end:
|
||||
if (td->ev.id == STREAM_FIND_END_TIME)
|
||||
{
|
||||
if (time != INVALID_TIMESTAMP)
|
||||
{
|
||||
time = TICKS_TO_TS(time);
|
||||
duration = TICKS_TO_TS(duration);
|
||||
sd->time = time + duration;
|
||||
retval = STREAM_PERFECT_MATCH;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = STREAM_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGF(" audio header: 0x%02X%02X%02X%02X\n",
|
||||
(unsigned)audio_queue.ptr[0], (unsigned)audio_queue.ptr[1],
|
||||
(unsigned)audio_queue.ptr[2], (unsigned)audio_queue.ptr[3]);
|
||||
|
||||
return retval;
|
||||
(void)td;
|
||||
}
|
||||
|
||||
static void audio_thread_msg(struct audio_thread_data *td)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
intptr_t reply = 0;
|
||||
|
||||
switch (td->ev.id)
|
||||
{
|
||||
case STREAM_PLAY:
|
||||
td->status = STREAM_PLAYING;
|
||||
|
||||
switch (td->state)
|
||||
{
|
||||
case TSTATE_INIT:
|
||||
td->state = TSTATE_DECODE;
|
||||
case TSTATE_DECODE:
|
||||
case TSTATE_RENDER_WAIT:
|
||||
break;
|
||||
|
||||
case TSTATE_EOS:
|
||||
/* At end of stream - no playback possible so fire the
|
||||
* completion event */
|
||||
stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STREAM_PAUSE:
|
||||
td->status = STREAM_PAUSED;
|
||||
reply = td->state != TSTATE_EOS;
|
||||
break;
|
||||
|
||||
case STREAM_STOP:
|
||||
if (td->state == TSTATE_DATA)
|
||||
stream_clear_notify(&audio_str, DISK_BUF_DATA_NOTIFY);
|
||||
|
||||
td->status = STREAM_STOPPED;
|
||||
td->state = TSTATE_EOS;
|
||||
|
||||
reply = true;
|
||||
break;
|
||||
|
||||
case STREAM_RESET:
|
||||
if (td->state == TSTATE_DATA)
|
||||
stream_clear_notify(&audio_str, DISK_BUF_DATA_NOTIFY);
|
||||
|
||||
td->status = STREAM_STOPPED;
|
||||
td->state = TSTATE_INIT;
|
||||
td->samplerate = 0;
|
||||
td->nchannels = 0;
|
||||
|
||||
init_mad();
|
||||
td->mad_errors = 0;
|
||||
|
||||
audio_queue_reset();
|
||||
|
||||
reply = true;
|
||||
break;
|
||||
|
||||
case STREAM_NEEDS_SYNC:
|
||||
reply = true; /* Audio always needs to */
|
||||
break;
|
||||
|
||||
case STREAM_SYNC:
|
||||
case STREAM_FIND_END_TIME:
|
||||
if (td->state != TSTATE_INIT)
|
||||
break;
|
||||
|
||||
reply = audio_sync(td, (struct str_sync_data *)td->ev.data);
|
||||
break;
|
||||
|
||||
case DISK_BUF_DATA_NOTIFY:
|
||||
/* Our bun is done */
|
||||
if (td->state != TSTATE_DATA)
|
||||
break;
|
||||
|
||||
td->state = TSTATE_DECODE;
|
||||
str_data_notify_received(&audio_str);
|
||||
break;
|
||||
|
||||
case STREAM_QUIT:
|
||||
/* Time to go - make thread exit */
|
||||
td->state = TSTATE_EOS;
|
||||
return;
|
||||
}
|
||||
|
||||
str_reply_msg(&audio_str, reply);
|
||||
|
||||
if (td->status == STREAM_PLAYING)
|
||||
{
|
||||
switch (td->state)
|
||||
{
|
||||
case TSTATE_DECODE:
|
||||
case TSTATE_RENDER_WAIT:
|
||||
/* These return when in playing state */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
str_get_msg(&audio_str, &td->ev);
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_thread(void)
|
||||
{
|
||||
struct audio_thread_data td;
|
||||
#ifdef HAVE_PRIORITY_SCHEDULING
|
||||
/* Up the priority since the core DSP over-yields internally */
|
||||
int old_priority = rb->thread_set_priority(rb->thread_self(),
|
||||
PRIORITY_PLAYBACK-4);
|
||||
#endif
|
||||
|
||||
rb->memset(&td, 0, sizeof (td));
|
||||
td.status = STREAM_STOPPED;
|
||||
td.state = TSTATE_EOS;
|
||||
|
||||
/* We need this here to init the EMAC for Coldfire targets */
|
||||
init_mad();
|
||||
|
||||
td.dsp = rb->dsp_get_config(CODEC_IDX_AUDIO);
|
||||
rb->dsp_configure(td.dsp, DSP_SET_OUT_FREQUENCY, CLOCK_RATE);
|
||||
#ifdef HAVE_PITCHCONTROL
|
||||
rb->sound_set_pitch(PITCH_SPEED_100);
|
||||
rb->dsp_set_timestretch(PITCH_SPEED_100);
|
||||
#endif
|
||||
rb->dsp_configure(td.dsp, DSP_RESET, 0);
|
||||
rb->dsp_configure(td.dsp, DSP_FLUSH, 0);
|
||||
rb->dsp_configure(td.dsp, DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS);
|
||||
|
||||
goto message_wait;
|
||||
|
||||
/* This is the decoding loop. */
|
||||
while (1)
|
||||
{
|
||||
td.state = TSTATE_DECODE;
|
||||
|
||||
/* Check for any pending messages and process them */
|
||||
if (str_have_msg(&audio_str))
|
||||
{
|
||||
message_wait:
|
||||
/* Wait for a message to be queued */
|
||||
str_get_msg(&audio_str, &td.ev);
|
||||
|
||||
message_process:
|
||||
/* Process a message already dequeued */
|
||||
audio_thread_msg(&td);
|
||||
|
||||
switch (td.state)
|
||||
{
|
||||
/* These states are the only ones that should return */
|
||||
case TSTATE_DECODE: goto audio_decode;
|
||||
case TSTATE_RENDER_WAIT: goto render_wait;
|
||||
/* Anything else is interpreted as an exit */
|
||||
default:
|
||||
{
|
||||
#ifdef HAVE_PRIORITY_SCHEDULING
|
||||
rb->thread_set_priority(rb->thread_self(), old_priority);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audio_decode:
|
||||
|
||||
/** Buffering **/
|
||||
switch (audio_buffer(&audio_str, STREAM_PM_STREAMING))
|
||||
{
|
||||
case STREAM_DATA_NOT_READY:
|
||||
{
|
||||
td.state = TSTATE_DATA;
|
||||
goto message_wait;
|
||||
} /* STREAM_DATA_NOT_READY: */
|
||||
|
||||
case STREAM_DATA_END:
|
||||
{
|
||||
if (audio_queue.used > MAD_BUFFER_GUARD)
|
||||
break; /* Still have frames to decode */
|
||||
|
||||
/* Used up remainder of compressed audio buffer. Wait for
|
||||
* samples on PCM buffer to finish playing. */
|
||||
audio_queue_reset();
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (pcm_output_empty())
|
||||
{
|
||||
td.state = TSTATE_EOS;
|
||||
stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
pcm_output_drain();
|
||||
str_get_msg_w_tmo(&audio_str, &td.ev, 1);
|
||||
|
||||
if (td.ev.id != SYS_TIMEOUT)
|
||||
break;
|
||||
}
|
||||
|
||||
goto message_wait;
|
||||
} /* STREAM_DATA_END: */
|
||||
}
|
||||
|
||||
/** Decoding **/
|
||||
mad_stream_buffer(&stream, audio_queue.ptr, audio_queue.used);
|
||||
|
||||
int mad_stat = mad_frame_decode(&frame, &stream);
|
||||
|
||||
ssize_t len = stream.next_frame - audio_queue.ptr;
|
||||
|
||||
if (mad_stat != 0)
|
||||
{
|
||||
DEBUGF("audio: Stream error: %s\n",
|
||||
mad_stream_errorstr(&stream));
|
||||
|
||||
/* If something's goofed - try to perform resync by moving
|
||||
* at least one byte at a time */
|
||||
audio_queue_advance_pos(MAX(len, 1));
|
||||
|
||||
if (stream.error == MAD_ERROR_BUFLEN)
|
||||
{
|
||||
/* This makes the codec support partially corrupted files */
|
||||
if (++td.mad_errors <= MPA_MAX_FRAME_SIZE)
|
||||
{
|
||||
stream.error = 0;
|
||||
rb->yield();
|
||||
continue;
|
||||
}
|
||||
DEBUGF("audio: Too many errors\n");
|
||||
}
|
||||
else if (MAD_RECOVERABLE(stream.error))
|
||||
{
|
||||
/* libmad says it can recover - just keep on decoding */
|
||||
rb->yield();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some other unrecoverable error */
|
||||
DEBUGF("audio: Unrecoverable error\n");
|
||||
}
|
||||
|
||||
/* This is too hard - bail out */
|
||||
td.state = TSTATE_EOS;
|
||||
td.status = STREAM_ERROR;
|
||||
stream_generate_event(&audio_str, STREAM_EV_COMPLETE, 0);
|
||||
|
||||
goto message_wait;
|
||||
}
|
||||
|
||||
/* Adjust sizes by the frame size */
|
||||
audio_queue_advance_pos(len);
|
||||
td.mad_errors = 0; /* Clear errors */
|
||||
|
||||
/* Generate the pcm samples */
|
||||
mad_synth_frame(&synth, &frame);
|
||||
|
||||
/** Output **/
|
||||
if (frame.header.samplerate != td.samplerate)
|
||||
{
|
||||
td.samplerate = frame.header.samplerate;
|
||||
rb->dsp_configure(td.dsp, DSP_SET_FREQUENCY,
|
||||
td.samplerate);
|
||||
}
|
||||
|
||||
if (MAD_NCHANNELS(&frame.header) != td.nchannels)
|
||||
{
|
||||
td.nchannels = MAD_NCHANNELS(&frame.header);
|
||||
rb->dsp_configure(td.dsp, DSP_SET_STEREO_MODE,
|
||||
td.nchannels == 1 ?
|
||||
STEREO_MONO : STEREO_NONINTERLEAVED);
|
||||
}
|
||||
|
||||
td.src.remcount = synth.pcm.length;
|
||||
td.src.pin[0] = synth.pcm.samples[0];
|
||||
td.src.pin[1] = synth.pcm.samples[1];
|
||||
td.src.proc_mask = 0;
|
||||
|
||||
td.state = TSTATE_RENDER_WAIT;
|
||||
|
||||
/* Add a frame of audio to the pcm buffer. Maximum is 1152 samples. */
|
||||
render_wait:
|
||||
rb->yield();
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct dsp_buffer dst;
|
||||
dst.remcount = 0;
|
||||
dst.bufcount = MAX(td.src.remcount, 1024);
|
||||
|
||||
ssize_t size = dst.bufcount * 2 * sizeof(int16_t);
|
||||
|
||||
/* Wait for required amount of free buffer space */
|
||||
while ((dst.p16out = pcm_output_get_buffer(&size)) == NULL)
|
||||
{
|
||||
/* Wait one frame */
|
||||
int timeout = dst.bufcount*HZ / td.samplerate;
|
||||
str_get_msg_w_tmo(&audio_str, &td.ev, MAX(timeout, 1));
|
||||
if (td.ev.id != SYS_TIMEOUT)
|
||||
goto message_process;
|
||||
}
|
||||
|
||||
dst.bufcount = size / (2 * sizeof (int16_t));
|
||||
rb->dsp_process(td.dsp, &td.src, &dst);
|
||||
|
||||
if (dst.remcount > 0)
|
||||
{
|
||||
/* Make this data available to DMA */
|
||||
pcm_output_commit_data(dst.remcount * 2 * sizeof(int16_t),
|
||||
audio_queue.curr->time);
|
||||
|
||||
/* As long as we're on this timestamp, the time is just
|
||||
incremented by the number of samples */
|
||||
audio_queue.curr->time += dst.remcount;
|
||||
}
|
||||
else if (td.src.remcount <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* end decoding loop */
|
||||
}
|
||||
|
||||
/* Initializes the audio thread resources and starts the thread */
|
||||
bool audio_thread_init(void)
|
||||
{
|
||||
/* Initialise the encoded audio buffer and its descriptors */
|
||||
audio_queue.start = mpeg_malloc(AUDIOBUF_ALLOC_SIZE,
|
||||
MPEG_ALLOC_AUDIOBUF);
|
||||
if (audio_queue.start == NULL)
|
||||
return false;
|
||||
|
||||
/* Start the audio thread */
|
||||
audio_str.hdr.q = &audio_str_queue;
|
||||
rb->queue_init(audio_str.hdr.q, false);
|
||||
|
||||
/* We steal the codec thread for audio */
|
||||
rb->codec_thread_do_callback(audio_thread, &audio_str.thread);
|
||||
|
||||
rb->queue_enable_queue_send(audio_str.hdr.q, &audio_str_queue_send,
|
||||
audio_str.thread);
|
||||
|
||||
/* Wait for thread to initialize */
|
||||
str_send_msg(&audio_str, STREAM_NULL, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Stops the audio thread */
|
||||
void audio_thread_exit(void)
|
||||
{
|
||||
if (audio_str.thread != 0)
|
||||
{
|
||||
str_post_msg(&audio_str, STREAM_QUIT, 0);
|
||||
rb->codec_thread_do_callback(NULL, NULL);
|
||||
audio_str.thread = 0;
|
||||
}
|
||||
}
|
|
@ -1,989 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* mpegplayer buffering routines
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "plugin.h"
|
||||
#include "mpegplayer.h"
|
||||
#include <system.h>
|
||||
|
||||
static struct mutex disk_buf_mtx SHAREDBSS_ATTR;
|
||||
static struct event_queue disk_buf_queue SHAREDBSS_ATTR;
|
||||
static struct queue_sender_list disk_buf_queue_send SHAREDBSS_ATTR;
|
||||
static uint32_t disk_buf_stack[DEFAULT_STACK_SIZE*2/sizeof(uint32_t)];
|
||||
|
||||
struct disk_buf disk_buf SHAREDBSS_ATTR;
|
||||
static void *nf_list[MPEGPLAYER_MAX_STREAMS+1];
|
||||
|
||||
static inline void disk_buf_lock(void)
|
||||
{
|
||||
rb->mutex_lock(&disk_buf_mtx);
|
||||
}
|
||||
|
||||
static inline void disk_buf_unlock(void)
|
||||
{
|
||||
rb->mutex_unlock(&disk_buf_mtx);
|
||||
}
|
||||
|
||||
static inline void disk_buf_on_clear_data_notify(struct stream_hdr *sh)
|
||||
{
|
||||
DEBUGF("DISK_BUF_CLEAR_DATA_NOTIFY: 0x%02X (cleared)\n",
|
||||
STR_FROM_HDR(sh)->id);
|
||||
list_remove_item(nf_list, sh);
|
||||
}
|
||||
|
||||
inline bool disk_buf_is_data_ready(struct stream_hdr *sh,
|
||||
ssize_t margin)
|
||||
{
|
||||
/* Data window available? */
|
||||
off_t right = sh->win_right;
|
||||
|
||||
/* Margins past end-of-file can still return true */
|
||||
if (right > disk_buf.filesize - margin)
|
||||
right = disk_buf.filesize - margin;
|
||||
|
||||
return sh->win_left >= disk_buf.win_left &&
|
||||
right + margin <= disk_buf.win_right;
|
||||
}
|
||||
|
||||
void dbuf_l2_init(struct dbuf_l2_cache *l2_p)
|
||||
{
|
||||
l2_p->addr = OFF_T_MAX; /* Mark as invalid */
|
||||
}
|
||||
|
||||
static int disk_buf_on_data_notify(struct stream_hdr *sh)
|
||||
{
|
||||
DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X ", STR_FROM_HDR(sh)->id);
|
||||
|
||||
if (sh->win_left <= sh->win_right)
|
||||
{
|
||||
/* Check if the data is already ready already */
|
||||
if (disk_buf_is_data_ready(sh, 0))
|
||||
{
|
||||
/* It was - don't register */
|
||||
DEBUGF("(was ready)\n"
|
||||
" swl:%lu swr:%lu\n"
|
||||
" dwl:%lu dwr:%lu\n",
|
||||
sh->win_left, sh->win_right,
|
||||
disk_buf.win_left, disk_buf.win_right);
|
||||
/* Be sure it's not listed though if multiple requests were made */
|
||||
list_remove_item(nf_list, sh);
|
||||
return DISK_BUF_NOTIFY_OK;
|
||||
}
|
||||
|
||||
switch (disk_buf.state)
|
||||
{
|
||||
case TSTATE_DATA:
|
||||
case TSTATE_BUFFERING:
|
||||
case TSTATE_INIT:
|
||||
disk_buf.state = TSTATE_BUFFERING;
|
||||
list_add_item(nf_list, sh);
|
||||
DEBUGF("(registered)\n"
|
||||
" swl:%lu swr:%lu\n"
|
||||
" dwl:%lu dwr:%lu\n",
|
||||
sh->win_left, sh->win_right,
|
||||
disk_buf.win_left, disk_buf.win_right);
|
||||
return DISK_BUF_NOTIFY_REGISTERED;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGF("(error)\n");
|
||||
return DISK_BUF_NOTIFY_ERROR;
|
||||
}
|
||||
|
||||
static bool check_data_notifies_callback(struct stream_hdr *sh, void *data)
|
||||
{
|
||||
if (disk_buf_is_data_ready(sh, 0))
|
||||
{
|
||||
/* Remove from list then post notification - post because send
|
||||
* could result in a wait for each thread to finish resulting
|
||||
* in deadlock */
|
||||
list_remove_item(nf_list, sh);
|
||||
str_post_msg(STR_FROM_HDR(sh), DISK_BUF_DATA_NOTIFY, 0);
|
||||
DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X (notified)\n",
|
||||
STR_FROM_HDR(sh)->id);
|
||||
}
|
||||
|
||||
return true;
|
||||
(void)data;
|
||||
}
|
||||
|
||||
/* Check registered streams and notify them if their data is available */
|
||||
static inline void check_data_notifies(void)
|
||||
{
|
||||
list_enum_items(nf_list,
|
||||
(list_enum_callback_t)check_data_notifies_callback,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Clear all registered notifications - do not post them */
|
||||
static inline void clear_data_notifies(void)
|
||||
{
|
||||
list_clear_all(nf_list);
|
||||
}
|
||||
|
||||
/* Background buffering when streaming */
|
||||
static inline void disk_buf_buffer(void)
|
||||
{
|
||||
struct stream_window sw;
|
||||
|
||||
switch (disk_buf.state)
|
||||
{
|
||||
default:
|
||||
{
|
||||
size_t wm;
|
||||
uint32_t time;
|
||||
|
||||
/* Get remaining minimum data based upon the stream closest to the
|
||||
* right edge of the window */
|
||||
if (!stream_get_window(&sw))
|
||||
break;
|
||||
|
||||
time = stream_get_ticks(NULL);
|
||||
wm = muldiv_uint32(5*CLOCK_RATE, sw.right - disk_buf.pos_last,
|
||||
time - disk_buf.time_last);
|
||||
wm = MIN(wm, (size_t)disk_buf.size);
|
||||
wm = MAX(wm, DISK_BUF_LOW_WATERMARK);
|
||||
|
||||
disk_buf.time_last = time;
|
||||
disk_buf.pos_last = sw.right;
|
||||
|
||||
/* Fast attack, slow decay */
|
||||
disk_buf.low_wm = (wm > (size_t)disk_buf.low_wm) ?
|
||||
wm : AVERAGE(disk_buf.low_wm, wm, 16);
|
||||
|
||||
#if 0
|
||||
rb->splashf(0, "*%10ld %10ld", disk_buf.low_wm,
|
||||
disk_buf.win_right - sw.right);
|
||||
#endif
|
||||
|
||||
if (disk_buf.win_right - sw.right > disk_buf.low_wm)
|
||||
break;
|
||||
|
||||
disk_buf.state = TSTATE_BUFFERING;
|
||||
} /* default: */
|
||||
|
||||
/* Fall-through */
|
||||
case TSTATE_BUFFERING:
|
||||
{
|
||||
ssize_t len, n;
|
||||
uint32_t tag, *tag_p;
|
||||
|
||||
/* Limit buffering up to the stream with the least progress */
|
||||
if (!stream_get_window(&sw))
|
||||
{
|
||||
disk_buf.state = TSTATE_DATA;
|
||||
rb->storage_sleep();
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wrap pointer */
|
||||
if (disk_buf.tail >= disk_buf.end)
|
||||
disk_buf.tail = disk_buf.start;
|
||||
|
||||
len = disk_buf.size - disk_buf.win_right + sw.left;
|
||||
|
||||
if (len < DISK_BUF_PAGE_SIZE)
|
||||
{
|
||||
/* Free space is less than one page */
|
||||
disk_buf.state = TSTATE_DATA;
|
||||
disk_buf.low_wm = DISK_BUF_LOW_WATERMARK;
|
||||
rb->storage_sleep();
|
||||
break;
|
||||
}
|
||||
|
||||
len = disk_buf.tail - disk_buf.start;
|
||||
tag = MAP_OFFSET_TO_TAG(disk_buf.win_right);
|
||||
tag_p = &disk_buf.cache[len >> DISK_BUF_PAGE_SHIFT];
|
||||
|
||||
if (*tag_p != tag)
|
||||
{
|
||||
if (disk_buf.need_seek)
|
||||
{
|
||||
rb->lseek(disk_buf.in_file, disk_buf.win_right, SEEK_SET);
|
||||
disk_buf.need_seek = false;
|
||||
}
|
||||
|
||||
n = rb->read(disk_buf.in_file, disk_buf.tail, DISK_BUF_PAGE_SIZE);
|
||||
|
||||
if (n <= 0)
|
||||
{
|
||||
/* Error or end of stream */
|
||||
disk_buf.state = TSTATE_EOS;
|
||||
rb->storage_sleep();
|
||||
break;
|
||||
}
|
||||
|
||||
if (len < DISK_GUARDBUF_SIZE)
|
||||
{
|
||||
/* Autoguard guard-o-rama - maintain guardbuffer coherency */
|
||||
rb->memcpy(disk_buf.end + len, disk_buf.tail,
|
||||
MIN(DISK_GUARDBUF_SIZE - len, n));
|
||||
}
|
||||
|
||||
/* Update the cache entry for this page */
|
||||
*tag_p = tag;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Skipping a read */
|
||||
n = MIN(DISK_BUF_PAGE_SIZE,
|
||||
disk_buf.filesize - disk_buf.win_right);
|
||||
disk_buf.need_seek = true;
|
||||
}
|
||||
|
||||
disk_buf.tail += DISK_BUF_PAGE_SIZE;
|
||||
|
||||
/* Keep left edge moving forward */
|
||||
|
||||
/* Advance right edge in temp variable first, then move
|
||||
* left edge if overflow would occur. This avoids a stream
|
||||
* thinking its data might be available when it actually
|
||||
* may not end up that way after a slide of the window. */
|
||||
len = disk_buf.win_right + n;
|
||||
|
||||
if (len - disk_buf.win_left > disk_buf.size)
|
||||
disk_buf.win_left += n;
|
||||
|
||||
disk_buf.win_right = len;
|
||||
|
||||
/* Continue buffering until filled or file end */
|
||||
rb->yield();
|
||||
} /* TSTATE_BUFFERING: */
|
||||
|
||||
case TSTATE_EOS:
|
||||
break;
|
||||
} /* end switch */
|
||||
}
|
||||
|
||||
static void disk_buf_on_reset(ssize_t pos)
|
||||
{
|
||||
int page;
|
||||
uint32_t tag;
|
||||
off_t anchor;
|
||||
|
||||
disk_buf.state = TSTATE_INIT;
|
||||
disk_buf.status = STREAM_STOPPED;
|
||||
clear_data_notifies();
|
||||
|
||||
if (pos >= disk_buf.filesize)
|
||||
{
|
||||
/* Anchor on page immediately following the one containing final
|
||||
* data */
|
||||
anchor = disk_buf.file_pages * DISK_BUF_PAGE_SIZE;
|
||||
disk_buf.win_left = disk_buf.filesize;
|
||||
}
|
||||
else
|
||||
{
|
||||
anchor = pos & ~DISK_BUF_PAGE_MASK;
|
||||
disk_buf.win_left = anchor;
|
||||
}
|
||||
|
||||
/* Collect all valid data already buffered that is contiguous with the
|
||||
* current position - probe to left, then to right */
|
||||
if (anchor > 0)
|
||||
{
|
||||
page = MAP_OFFSET_TO_PAGE(anchor);
|
||||
tag = MAP_OFFSET_TO_TAG(anchor);
|
||||
|
||||
do
|
||||
{
|
||||
if (--tag, --page < 0)
|
||||
page = disk_buf.pgcount - 1;
|
||||
|
||||
if (disk_buf.cache[page] != tag)
|
||||
break;
|
||||
|
||||
disk_buf.win_left = tag << DISK_BUF_PAGE_SHIFT;
|
||||
}
|
||||
while (tag > 0);
|
||||
}
|
||||
|
||||
if (anchor < disk_buf.filesize)
|
||||
{
|
||||
page = MAP_OFFSET_TO_PAGE(anchor);
|
||||
tag = MAP_OFFSET_TO_TAG(anchor);
|
||||
|
||||
do
|
||||
{
|
||||
if (disk_buf.cache[page] != tag)
|
||||
break;
|
||||
|
||||
if (++tag, ++page >= disk_buf.pgcount)
|
||||
page = 0;
|
||||
|
||||
anchor += DISK_BUF_PAGE_SIZE;
|
||||
}
|
||||
while (anchor < disk_buf.filesize);
|
||||
}
|
||||
|
||||
if (anchor >= disk_buf.filesize)
|
||||
{
|
||||
disk_buf.win_right = disk_buf.filesize;
|
||||
disk_buf.state = TSTATE_EOS;
|
||||
}
|
||||
else
|
||||
{
|
||||
disk_buf.win_right = anchor;
|
||||
}
|
||||
|
||||
disk_buf.tail = disk_buf.start + MAP_OFFSET_TO_BUFFER(anchor);
|
||||
|
||||
DEBUGF("disk buf reset\n"
|
||||
" dwl:%ld dwr:%ld\n",
|
||||
disk_buf.win_left, disk_buf.win_right);
|
||||
|
||||
/* Next read position is at right edge */
|
||||
rb->lseek(disk_buf.in_file, disk_buf.win_right, SEEK_SET);
|
||||
disk_buf.need_seek = false;
|
||||
|
||||
disk_buf_reply_msg(disk_buf.win_right - disk_buf.win_left);
|
||||
}
|
||||
|
||||
static void disk_buf_on_stop(void)
|
||||
{
|
||||
bool was_buffering = disk_buf.state == TSTATE_BUFFERING;
|
||||
|
||||
disk_buf.state = TSTATE_EOS;
|
||||
disk_buf.status = STREAM_STOPPED;
|
||||
clear_data_notifies();
|
||||
|
||||
disk_buf_reply_msg(was_buffering);
|
||||
}
|
||||
|
||||
static void disk_buf_on_play_pause(bool play, bool forcefill)
|
||||
{
|
||||
struct stream_window sw;
|
||||
|
||||
if (disk_buf.state != TSTATE_EOS)
|
||||
{
|
||||
if (forcefill)
|
||||
{
|
||||
/* Force buffer filling to top */
|
||||
disk_buf.state = TSTATE_BUFFERING;
|
||||
}
|
||||
else if (disk_buf.state != TSTATE_BUFFERING)
|
||||
{
|
||||
/* If not filling already, simply monitor */
|
||||
disk_buf.state = TSTATE_DATA;
|
||||
}
|
||||
}
|
||||
/* else end of stream - no buffering to do */
|
||||
|
||||
disk_buf.pos_last = stream_get_window(&sw) ? sw.right : 0;
|
||||
disk_buf.time_last = stream_get_ticks(NULL);
|
||||
|
||||
disk_buf.status = play ? STREAM_PLAYING : STREAM_PAUSED;
|
||||
}
|
||||
|
||||
static int disk_buf_on_load_range(struct dbuf_range *rng)
|
||||
{
|
||||
uint32_t tag = rng->tag_start;
|
||||
uint32_t tag_end = rng->tag_end;
|
||||
int page = rng->pg_start;
|
||||
|
||||
/* Check if a seek is required */
|
||||
bool need_seek = rb->lseek(disk_buf.in_file, 0, SEEK_CUR)
|
||||
!= (off_t)(tag << DISK_BUF_PAGE_SHIFT);
|
||||
|
||||
do
|
||||
{
|
||||
uint32_t *tag_p = &disk_buf.cache[page];
|
||||
|
||||
if (*tag_p != tag)
|
||||
{
|
||||
/* Page not cached - load it */
|
||||
ssize_t o, n;
|
||||
|
||||
if (need_seek)
|
||||
{
|
||||
rb->lseek(disk_buf.in_file, tag << DISK_BUF_PAGE_SHIFT,
|
||||
SEEK_SET);
|
||||
need_seek = false;
|
||||
}
|
||||
|
||||
o = page << DISK_BUF_PAGE_SHIFT;
|
||||
n = rb->read(disk_buf.in_file, disk_buf.start + o,
|
||||
DISK_BUF_PAGE_SIZE);
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
/* Read error */
|
||||
return DISK_BUF_NOTIFY_ERROR;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
/* End of file */
|
||||
break;
|
||||
}
|
||||
|
||||
if (o < DISK_GUARDBUF_SIZE)
|
||||
{
|
||||
/* Autoguard guard-o-rama - maintain guardbuffer coherency */
|
||||
rb->memcpy(disk_buf.end + o, disk_buf.start + o,
|
||||
MIN(DISK_GUARDBUF_SIZE - o, n));
|
||||
}
|
||||
|
||||
/* Update the cache entry */
|
||||
*tag_p = tag;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Skipping a disk read - must seek on next one */
|
||||
need_seek = true;
|
||||
}
|
||||
|
||||
if (++page >= disk_buf.pgcount)
|
||||
page = 0;
|
||||
}
|
||||
while (++tag <= tag_end);
|
||||
|
||||
return DISK_BUF_NOTIFY_OK;
|
||||
}
|
||||
|
||||
static void disk_buf_thread(void)
|
||||
{
|
||||
struct queue_event ev;
|
||||
|
||||
disk_buf.state = TSTATE_EOS;
|
||||
disk_buf.status = STREAM_STOPPED;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (disk_buf.state != TSTATE_EOS)
|
||||
{
|
||||
/* Poll buffer status and messages */
|
||||
rb->queue_wait_w_tmo(disk_buf.q, &ev,
|
||||
disk_buf.state == TSTATE_BUFFERING ?
|
||||
0 : HZ/5);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Sit idle and wait for commands */
|
||||
rb->queue_wait(disk_buf.q, &ev);
|
||||
}
|
||||
|
||||
switch (ev.id)
|
||||
{
|
||||
case SYS_TIMEOUT:
|
||||
if (disk_buf.state == TSTATE_EOS)
|
||||
break;
|
||||
|
||||
disk_buf_buffer();
|
||||
|
||||
/* Check for any due notifications if any are pending */
|
||||
if (*nf_list != NULL)
|
||||
check_data_notifies();
|
||||
|
||||
/* Still more data left? */
|
||||
if (disk_buf.state != TSTATE_EOS)
|
||||
continue;
|
||||
|
||||
/* Nope - end of stream */
|
||||
break;
|
||||
|
||||
case DISK_BUF_CACHE_RANGE:
|
||||
disk_buf_reply_msg(disk_buf_on_load_range(
|
||||
(struct dbuf_range *)ev.data));
|
||||
break;
|
||||
|
||||
case STREAM_RESET:
|
||||
disk_buf_on_reset(ev.data);
|
||||
break;
|
||||
|
||||
case STREAM_STOP:
|
||||
disk_buf_on_stop();
|
||||
break;
|
||||
|
||||
case STREAM_PAUSE:
|
||||
case STREAM_PLAY:
|
||||
disk_buf_on_play_pause(ev.id == STREAM_PLAY, ev.data != 0);
|
||||
disk_buf_reply_msg(1);
|
||||
break;
|
||||
|
||||
case STREAM_QUIT:
|
||||
disk_buf.state = TSTATE_EOS;
|
||||
return;
|
||||
|
||||
case DISK_BUF_DATA_NOTIFY:
|
||||
disk_buf_reply_msg(disk_buf_on_data_notify(
|
||||
(struct stream_hdr *)ev.data));
|
||||
break;
|
||||
|
||||
case DISK_BUF_CLEAR_DATA_NOTIFY:
|
||||
disk_buf_on_clear_data_notify((struct stream_hdr *)ev.data);
|
||||
disk_buf_reply_msg(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Caches some data from the current file */
|
||||
static ssize_t disk_buf_probe(off_t start, size_t length, void **p)
|
||||
{
|
||||
off_t end;
|
||||
uint32_t tag, tag_end;
|
||||
int page;
|
||||
|
||||
/* Can't read past end of file */
|
||||
if (length > (size_t)(disk_buf.filesize - start))
|
||||
{
|
||||
length = disk_buf.filesize - start;
|
||||
}
|
||||
|
||||
/* Can't cache more than the whole buffer size */
|
||||
if (length > (size_t)disk_buf.size)
|
||||
{
|
||||
length = disk_buf.size;
|
||||
}
|
||||
/* Zero-length probes permitted */
|
||||
|
||||
end = start + length;
|
||||
|
||||
/* Prepare the range probe */
|
||||
tag = MAP_OFFSET_TO_TAG(start);
|
||||
tag_end = MAP_OFFSET_TO_TAG(end);
|
||||
page = MAP_OFFSET_TO_PAGE(start);
|
||||
|
||||
/* If the end is on a page boundary, check one less or an extra
|
||||
* one will be probed */
|
||||
if (tag_end > tag && (end & DISK_BUF_PAGE_MASK) == 0)
|
||||
{
|
||||
tag_end--;
|
||||
}
|
||||
|
||||
if (p != NULL)
|
||||
{
|
||||
*p = disk_buf.start + (page << DISK_BUF_PAGE_SHIFT)
|
||||
+ (start & DISK_BUF_PAGE_MASK);
|
||||
}
|
||||
|
||||
/* Obtain initial load point. If all data was cached, no message is sent
|
||||
* otherwise begin on the first page that is not cached. Since we have to
|
||||
* send the message anyway, the buffering thread will determine what else
|
||||
* requires loading on its end in order to cache the specified range. */
|
||||
do
|
||||
{
|
||||
if (disk_buf.cache[page] != tag)
|
||||
{
|
||||
static struct dbuf_range rng IBSS_ATTR;
|
||||
intptr_t result;
|
||||
|
||||
DEBUGF("disk_buf: cache miss\n");
|
||||
rng.tag_start = tag;
|
||||
rng.tag_end = tag_end;
|
||||
rng.pg_start = page;
|
||||
|
||||
result = rb->queue_send(disk_buf.q, DISK_BUF_CACHE_RANGE,
|
||||
(intptr_t)&rng);
|
||||
|
||||
return result == DISK_BUF_NOTIFY_OK ? (ssize_t)length : -1;
|
||||
}
|
||||
|
||||
if (++page >= disk_buf.pgcount)
|
||||
page = 0;
|
||||
}
|
||||
while (++tag <= tag_end);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/* Attempt to get a pointer to size bytes on the buffer. Returns real amount of
|
||||
* data available as well as the size of non-wrapped data after *p. */
|
||||
ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap,
|
||||
size_t *sizewrap)
|
||||
{
|
||||
disk_buf_lock();
|
||||
|
||||
size = disk_buf_probe(disk_buf.offset, size, pp);
|
||||
|
||||
if (size != (size_t)-1 && pwrap && sizewrap)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)*pp;
|
||||
|
||||
if (p + size > disk_buf.end + DISK_GUARDBUF_SIZE)
|
||||
{
|
||||
/* Return pointer to wraparound and the size of same */
|
||||
size_t nowrap = (disk_buf.end + DISK_GUARDBUF_SIZE) - p;
|
||||
*pwrap = disk_buf.start + DISK_GUARDBUF_SIZE;
|
||||
*sizewrap = size - nowrap;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pwrap = NULL;
|
||||
*sizewrap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
disk_buf_unlock();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
ssize_t _disk_buf_getbuffer_l2(struct dbuf_l2_cache *l2,
|
||||
size_t size, void **pp)
|
||||
{
|
||||
off_t offs;
|
||||
off_t l2_addr;
|
||||
size_t l2_size;
|
||||
void *l2_p;
|
||||
|
||||
if (l2 == NULL)
|
||||
{
|
||||
/* Shouldn't have to check this normally */
|
||||
DEBUGF("disk_buf_getbuffer_l2: l2 = NULL!\n");
|
||||
}
|
||||
|
||||
if (size > DISK_BUF_L2_CACHE_SIZE)
|
||||
{
|
||||
/* Asking for too much; just go through L1 */
|
||||
return disk_buf_getbuffer(size, pp, NULL, NULL);
|
||||
}
|
||||
|
||||
offs = disk_buf.offset; /* Other calls keep this within bounds */
|
||||
l2_addr = l2->addr;
|
||||
|
||||
if (offs >= l2_addr && offs < l2_addr + DISK_BUF_L2_CACHE_SIZE)
|
||||
{
|
||||
/* Data is in the local buffer */
|
||||
offs &= DISK_BUF_L2_CACHE_MASK;
|
||||
|
||||
*pp = l2->data + offs;
|
||||
if (offs + size > l2->size)
|
||||
size = l2->size - offs; /* Keep size within file limits */
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Have to probe main buffer */
|
||||
l2_addr = offs & ~DISK_BUF_L2_CACHE_MASK;
|
||||
l2_size = DISK_BUF_L2_CACHE_SIZE*2; /* 2nd half is a guard buffer */
|
||||
|
||||
disk_buf_lock();
|
||||
|
||||
l2_size = disk_buf_probe(l2_addr, l2_size, &l2_p);
|
||||
|
||||
if (l2_size != (size_t)-1)
|
||||
{
|
||||
rb->memcpy(l2->data, l2_p, l2_size);
|
||||
|
||||
l2->addr = l2_addr;
|
||||
l2->size = l2_size;
|
||||
offs -= l2_addr;
|
||||
|
||||
*pp = l2->data + offs;
|
||||
if (offs + size > l2->size)
|
||||
size = l2->size - offs; /* Keep size within file limits */
|
||||
}
|
||||
else
|
||||
{
|
||||
size = -1;
|
||||
}
|
||||
|
||||
disk_buf_unlock();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/* Read size bytes of data into a buffer - advances the buffer pointer
|
||||
* and returns the real size read. */
|
||||
ssize_t disk_buf_read(void *buffer, size_t size)
|
||||
{
|
||||
uint8_t *p;
|
||||
|
||||
disk_buf_lock();
|
||||
|
||||
size = disk_buf_probe(disk_buf.offset, size, PUN_PTR(void **, &p));
|
||||
|
||||
if (size != (size_t)-1)
|
||||
{
|
||||
if (p + size > disk_buf.end + DISK_GUARDBUF_SIZE)
|
||||
{
|
||||
/* Read wraps */
|
||||
size_t nowrap = (disk_buf.end + DISK_GUARDBUF_SIZE) - p;
|
||||
rb->memcpy(buffer, p, nowrap);
|
||||
rb->memcpy(buffer + nowrap, disk_buf.start + DISK_GUARDBUF_SIZE,
|
||||
size - nowrap);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read wasn't wrapped or guardbuffer holds it */
|
||||
rb->memcpy(buffer, p, size);
|
||||
}
|
||||
|
||||
disk_buf.offset += size;
|
||||
}
|
||||
|
||||
disk_buf_unlock();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
ssize_t disk_buf_lseek(off_t offset, int whence)
|
||||
{
|
||||
disk_buf_lock();
|
||||
|
||||
/* The offset returned is the result of the current thread's action and
|
||||
* may be invalidated so a local result is returned and not the value
|
||||
* of disk_buf.offset directly */
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
/* offset is just the offset */
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
offset += disk_buf.offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
offset = disk_buf.filesize + offset;
|
||||
break;
|
||||
default:
|
||||
disk_buf_unlock();
|
||||
return -2; /* Invalid request */
|
||||
}
|
||||
|
||||
if (offset < 0 || offset > disk_buf.filesize)
|
||||
{
|
||||
offset = -3;
|
||||
}
|
||||
else
|
||||
{
|
||||
disk_buf.offset = offset;
|
||||
}
|
||||
|
||||
disk_buf_unlock();
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/* Prepare the buffer to enter the streaming state. Evaluates the available
|
||||
* streaming window. */
|
||||
ssize_t disk_buf_prepare_streaming(off_t pos, size_t len)
|
||||
{
|
||||
disk_buf_lock();
|
||||
|
||||
if (pos < 0)
|
||||
pos = 0;
|
||||
else if (pos > disk_buf.filesize)
|
||||
pos = disk_buf.filesize;
|
||||
|
||||
DEBUGF("prepare streaming:\n pos:%ld len:%lu\n", pos, (unsigned long)len);
|
||||
|
||||
pos = disk_buf_lseek(pos, SEEK_SET);
|
||||
len = disk_buf_probe(pos, len, NULL);
|
||||
|
||||
DEBUGF(" probe done: pos:%ld len:%lu\n", pos, (unsigned long)len);
|
||||
|
||||
len = disk_buf_send_msg(STREAM_RESET, pos);
|
||||
|
||||
disk_buf_unlock();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Set the streaming window to an arbitrary position within the file. Makes no
|
||||
* probes to validate data. Use after calling another function to cause data
|
||||
* to be cached and correct values are known. */
|
||||
ssize_t disk_buf_set_streaming_window(off_t left, off_t right)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
disk_buf_lock();
|
||||
|
||||
if (left < 0)
|
||||
left = 0;
|
||||
else if (left > disk_buf.filesize)
|
||||
left = disk_buf.filesize;
|
||||
|
||||
if (left > right)
|
||||
right = left;
|
||||
|
||||
if (right > disk_buf.filesize)
|
||||
right = disk_buf.filesize;
|
||||
|
||||
disk_buf.win_left = left;
|
||||
disk_buf.win_right = right;
|
||||
disk_buf.tail = disk_buf.start + ((right + DISK_BUF_PAGE_SIZE-1) &
|
||||
~DISK_BUF_PAGE_MASK) % disk_buf.size;
|
||||
|
||||
len = disk_buf.win_right - disk_buf.win_left;
|
||||
|
||||
disk_buf_unlock();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void * disk_buf_offset2ptr(off_t offset)
|
||||
{
|
||||
if (offset < 0)
|
||||
offset = 0;
|
||||
else if (offset > disk_buf.filesize)
|
||||
offset = disk_buf.filesize;
|
||||
|
||||
return disk_buf.start + (offset % disk_buf.size);
|
||||
}
|
||||
|
||||
void disk_buf_close(void)
|
||||
{
|
||||
disk_buf_lock();
|
||||
|
||||
if (disk_buf.in_file >= 0)
|
||||
{
|
||||
rb->close(disk_buf.in_file);
|
||||
disk_buf.in_file = -1;
|
||||
|
||||
/* Invalidate entire cache */
|
||||
rb->memset(disk_buf.cache, 0xff,
|
||||
disk_buf.pgcount*sizeof (*disk_buf.cache));
|
||||
disk_buf.file_pages = 0;
|
||||
disk_buf.filesize = 0;
|
||||
disk_buf.offset = 0;
|
||||
}
|
||||
|
||||
disk_buf_unlock();
|
||||
}
|
||||
|
||||
int disk_buf_open(const char *filename)
|
||||
{
|
||||
int fd;
|
||||
|
||||
disk_buf_lock();
|
||||
|
||||
disk_buf_close();
|
||||
|
||||
fd = rb->open(filename, O_RDONLY);
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
ssize_t filesize = rb->filesize(fd);
|
||||
|
||||
if (filesize <= 0)
|
||||
{
|
||||
rb->close(disk_buf.in_file);
|
||||
}
|
||||
else
|
||||
{
|
||||
disk_buf.filesize = filesize;
|
||||
/* Number of file pages rounded up toward +inf */
|
||||
disk_buf.file_pages = ((size_t)filesize + DISK_BUF_PAGE_SIZE-1)
|
||||
/ DISK_BUF_PAGE_SIZE;
|
||||
disk_buf.in_file = fd;
|
||||
}
|
||||
}
|
||||
|
||||
disk_buf_unlock();
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
intptr_t disk_buf_send_msg(long id, intptr_t data)
|
||||
{
|
||||
return rb->queue_send(disk_buf.q, id, data);
|
||||
}
|
||||
|
||||
void disk_buf_post_msg(long id, intptr_t data)
|
||||
{
|
||||
rb->queue_post(disk_buf.q, id, data);
|
||||
}
|
||||
|
||||
void disk_buf_reply_msg(intptr_t retval)
|
||||
{
|
||||
rb->queue_reply(disk_buf.q, retval);
|
||||
}
|
||||
|
||||
bool disk_buf_init(void)
|
||||
{
|
||||
disk_buf.thread = 0;
|
||||
|
||||
rb->mutex_init(&disk_buf_mtx);
|
||||
|
||||
disk_buf.q = &disk_buf_queue;
|
||||
rb->queue_init(disk_buf.q, false);
|
||||
|
||||
disk_buf.state = TSTATE_EOS;
|
||||
disk_buf.status = STREAM_STOPPED;
|
||||
|
||||
disk_buf.in_file = -1;
|
||||
disk_buf.filesize = 0;
|
||||
disk_buf.win_left = 0;
|
||||
disk_buf.win_right = 0;
|
||||
disk_buf.time_last = 0;
|
||||
disk_buf.pos_last = 0;
|
||||
disk_buf.low_wm = DISK_BUF_LOW_WATERMARK;
|
||||
|
||||
disk_buf.start = mpeg_malloc_all((size_t*)&disk_buf.size, MPEG_ALLOC_DISKBUF);
|
||||
if (disk_buf.start == NULL)
|
||||
return false;
|
||||
|
||||
#if NUM_CORES > 1
|
||||
CACHEALIGN_BUFFER(disk_buf.start, disk_buf.size);
|
||||
disk_buf.start = UNCACHED_ADDR(disk_buf.start);
|
||||
#endif
|
||||
disk_buf.size -= DISK_GUARDBUF_SIZE;
|
||||
disk_buf.pgcount = disk_buf.size / DISK_BUF_PAGE_SIZE;
|
||||
|
||||
/* Fit it as tightly as possible */
|
||||
while (disk_buf.pgcount*(sizeof (*disk_buf.cache) + DISK_BUF_PAGE_SIZE)
|
||||
> (size_t)disk_buf.size)
|
||||
{
|
||||
disk_buf.pgcount--;
|
||||
}
|
||||
|
||||
disk_buf.cache = (typeof (disk_buf.cache))disk_buf.start;
|
||||
disk_buf.start += sizeof (*disk_buf.cache)*disk_buf.pgcount;
|
||||
disk_buf.size = disk_buf.pgcount*DISK_BUF_PAGE_SIZE;
|
||||
disk_buf.end = disk_buf.start + disk_buf.size;
|
||||
disk_buf.tail = disk_buf.start;
|
||||
|
||||
DEBUGF("disk_buf info:\n"
|
||||
" page count: %d\n"
|
||||
" size: %ld\n",
|
||||
disk_buf.pgcount, (long)disk_buf.size);
|
||||
|
||||
rb->memset(disk_buf.cache, 0xff,
|
||||
disk_buf.pgcount*sizeof (*disk_buf.cache));
|
||||
|
||||
disk_buf.thread = rb->create_thread(
|
||||
disk_buf_thread, disk_buf_stack, sizeof(disk_buf_stack), 0,
|
||||
"mpgbuffer" IF_PRIO(, PRIORITY_BUFFERING) IF_COP(, CPU));
|
||||
|
||||
rb->queue_enable_queue_send(disk_buf.q, &disk_buf_queue_send,
|
||||
disk_buf.thread);
|
||||
|
||||
if (disk_buf.thread == 0)
|
||||
return false;
|
||||
|
||||
/* Wait for thread to initialize */
|
||||
disk_buf_send_msg(STREAM_NULL, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void disk_buf_exit(void)
|
||||
{
|
||||
if (disk_buf.thread != 0)
|
||||
{
|
||||
rb->queue_post(disk_buf.q, STREAM_QUIT, 0);
|
||||
rb->thread_wait(disk_buf.thread);
|
||||
disk_buf.thread = 0;
|
||||
}
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* AV disk buffer declarations
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef DISK_BUF_H
|
||||
#define DISK_BUF_H
|
||||
|
||||
#ifndef OFF_T_MAX
|
||||
#define OFF_T_MAX (~((off_t)1 << (sizeof (off_t)*8 - 1)))
|
||||
#endif
|
||||
|
||||
#ifndef OFF_T_MIN
|
||||
#define OFF_T_MIN ((off_t)1 << (sizeof (off_t)*8 - 1))
|
||||
#endif
|
||||
|
||||
#define DISK_BUF_PAGE_SHIFT 15 /* 32KB cache lines */
|
||||
#define DISK_BUF_PAGE_SIZE (1 << DISK_BUF_PAGE_SHIFT)
|
||||
#define DISK_BUF_PAGE_MASK (DISK_BUF_PAGE_SIZE-1)
|
||||
|
||||
enum
|
||||
{
|
||||
DISK_BUF_NOTIFY_ERROR = -1,
|
||||
DISK_BUF_NOTIFY_NULL = 0,
|
||||
DISK_BUF_NOTIFY_OK,
|
||||
DISK_BUF_NOTIFY_TIMEDOUT,
|
||||
DISK_BUF_NOTIFY_PROCESS_EVENT,
|
||||
DISK_BUF_NOTIFY_REGISTERED,
|
||||
};
|
||||
|
||||
/** Macros to map file offsets to cached data **/
|
||||
|
||||
/* Returns a cache tag given a file offset */
|
||||
#define MAP_OFFSET_TO_TAG(o) \
|
||||
((o) >> DISK_BUF_PAGE_SHIFT)
|
||||
|
||||
/* Returns the cache page number given a file offset */
|
||||
#define MAP_OFFSET_TO_PAGE(o) \
|
||||
(MAP_OFFSET_TO_TAG(o) % disk_buf.pgcount)
|
||||
|
||||
/* Returns the buffer offset given a file offset */
|
||||
#define MAP_OFFSET_TO_BUFFER(o) \
|
||||
(MAP_OFFSET_TO_PAGE(o) * DISK_BUF_PAGE_SIZE)
|
||||
|
||||
struct dbuf_range
|
||||
{
|
||||
uint32_t tag_start;
|
||||
uint32_t tag_end;
|
||||
int pg_start;
|
||||
};
|
||||
|
||||
#define DISK_BUF_L2_CACHE_SHIFT 6
|
||||
#define DISK_BUF_L2_CACHE_SIZE (1 << DISK_BUF_L2_CACHE_SHIFT)
|
||||
#define DISK_BUF_L2_CACHE_MASK (DISK_BUF_L2_CACHE_SIZE-1)
|
||||
|
||||
struct dbuf_l2_cache
|
||||
{
|
||||
off_t addr; /* L2 file offset */
|
||||
size_t size; /* Real size */
|
||||
uint8_t data[DISK_BUF_L2_CACHE_SIZE*2]; /* Local data and guard */
|
||||
};
|
||||
|
||||
void dbuf_l2_init(struct dbuf_l2_cache *l2_p);
|
||||
|
||||
/* This object is an extension of the stream manager and handles some
|
||||
* playback events as well as buffering */
|
||||
struct disk_buf
|
||||
{
|
||||
unsigned int thread;
|
||||
struct event_queue *q;
|
||||
uint8_t *start; /* Start pointer */
|
||||
uint8_t *end; /* End of buffer pointer less MPEG_GUARDBUF_SIZE. The
|
||||
guard space is used to wrap data at the buffer start to
|
||||
pass continuous data packets */
|
||||
uint8_t *tail; /* Location of last data + 1 filled into the buffer */
|
||||
ssize_t size; /* The buffer length _not_ including the guard space (end-start) */
|
||||
int pgcount; /* Total number of available cached pages */
|
||||
uint32_t *cache; /* Pointer to cache structure - allocated on buffer */
|
||||
int in_file; /* File being read */
|
||||
ssize_t filesize; /* Size of file in_file in bytes */
|
||||
int file_pages; /* Number of pages in file (rounded up) */
|
||||
off_t offset; /* Current position (random access) */
|
||||
off_t win_left; /* Left edge of buffer window (streaming) */
|
||||
off_t win_right; /* Right edge of buffer window (streaming) */
|
||||
uint32_t time_last; /* Last time watermark was checked */
|
||||
off_t pos_last; /* Last position at watermark check time */
|
||||
ssize_t low_wm; /* The low watermark for automatic rebuffering */
|
||||
int status; /* Status as stream */
|
||||
int state; /* Current thread state */
|
||||
bool need_seek; /* Need to seek because a read was not contiguous */
|
||||
};
|
||||
|
||||
extern struct disk_buf disk_buf SHAREDBSS_ATTR;
|
||||
|
||||
struct stream_hdr;
|
||||
bool disk_buf_is_data_ready(struct stream_hdr *sh, ssize_t margin);
|
||||
|
||||
bool disk_buf_init(void);
|
||||
void disk_buf_exit(void);
|
||||
|
||||
static inline int disk_buf_status(void)
|
||||
{ return disk_buf.status; }
|
||||
|
||||
int disk_buf_open(const char *filename);
|
||||
void disk_buf_close(void);
|
||||
ssize_t _disk_buf_getbuffer(size_t size, void **pp, void **pwrap,
|
||||
size_t *sizewrap);
|
||||
#define disk_buf_getbuffer(size, pp, pwrap, sizewrap) \
|
||||
_disk_buf_getbuffer((size), PUN_PTR(void **, (pp)), \
|
||||
PUN_PTR(void **, (pwrap)), (sizewrap))
|
||||
|
||||
ssize_t _disk_buf_getbuffer_l2(struct dbuf_l2_cache *l2,
|
||||
size_t size, void **pp);
|
||||
#define disk_buf_getbuffer_l2(l2, size, pp) \
|
||||
_disk_buf_getbuffer_l2((l2), (size), PUN_PTR(void **, (pp)))
|
||||
|
||||
ssize_t disk_buf_read(void *buffer, size_t size);
|
||||
ssize_t disk_buf_lseek(off_t offset, int whence);
|
||||
|
||||
static inline off_t disk_buf_ftell(void)
|
||||
{ return disk_buf.offset; }
|
||||
|
||||
static inline ssize_t disk_buf_filesize(void)
|
||||
{ return disk_buf.filesize; }
|
||||
|
||||
ssize_t disk_buf_prepare_streaming(off_t pos, size_t len);
|
||||
ssize_t disk_buf_set_streaming_window(off_t left, off_t right);
|
||||
void * disk_buf_offset2ptr(off_t offset);
|
||||
int disk_buf_check_streaming_window(off_t left, off_t right);
|
||||
|
||||
intptr_t disk_buf_send_msg(long id, intptr_t data);
|
||||
void disk_buf_post_msg(long id, intptr_t data);
|
||||
void disk_buf_reply_msg(intptr_t retval);
|
||||
|
||||
#endif /* DISK_BUF_H */
|
|
@ -1,33 +0,0 @@
|
|||
Aaron Holtzman <aholtzma@ess.engr.uvic.ca> started the project and
|
||||
made the initial working implementation.
|
||||
|
||||
Michel Lespinasse <walken@zoy.org> did major changes for speed and
|
||||
mpeg conformance and is the current maintainer. Most of the current
|
||||
code was (re)written by him.
|
||||
|
||||
Other contributors include:
|
||||
Bruno Barreyra <barreyra@ufl.edu> - build fixes
|
||||
Gildas Bazin <gbazin@netcourrier.com> - mingw32 port
|
||||
Alexander W. Chin <alexc@newt.phys.unsw.edu.au> - progressive_seq fix
|
||||
Stephen Crowley <stephenc@dns2.digitalpassage.com> - build fixes
|
||||
Didier Gautheron <dgautheron@magic.fr> - bug fixes
|
||||
Ryan C. Gordon <icculus@lokigames.com> - SDL support
|
||||
Peter Gubanov <peter@elecard.net.ru> - MMX IDCT scheduling
|
||||
Håkan Hjort <d95hjort@dtek.chalmers.se> - Solaris fixes, mlib code
|
||||
Nicolas Joly <njoly@pasteur.fr> - assorted bug fixes
|
||||
Gerd Knorr <kraxel@goldbach.in-berlin.de> - Xv support
|
||||
David I. Lehn <dlehn@vt.edu> - motion_comp mmx code
|
||||
Olie Lho <ollie@sis.com.tw> - MMX yuv2rgb routine
|
||||
David S. Miller <davem@redhat.com> - sparc VIS optimizations
|
||||
Rick Niles <niles@scyld.com> - build fixes
|
||||
Real Ouellet <realo@sympatico.ca> - g200 fixes
|
||||
Bajusz Peter <hyp-x@inf.bme.hu> - motion comp fixes
|
||||
Franck Sicard <Franck.Sicard@miniruth.solsoft.fr> - x11 fixes
|
||||
Brion Vibber <brion@gizmo.usc.edu> - x11 fixes
|
||||
Martin Vogt <mvogt@rhrk.uni-kl.de> - reentrancy fixes
|
||||
Fredrik Vraalsen <vraalsen@cs.uiuc.edu> - general hackage and stuff
|
||||
|
||||
(let me know if I forgot anyone)
|
||||
|
||||
Thanks to David Schleef for creating me an account on his ppc g4
|
||||
machine and making it possible for me to work on the altivec code.
|
|
@ -1,204 +0,0 @@
|
|||
|
||||
|
||||
ABOUT LIBMPEG2
|
||||
|
||||
libmpeg2 is a free library for decoding mpeg-2 and mpeg-1 video
|
||||
streams. It is released under the terms of the GPL license.
|
||||
|
||||
The main goals in libmpeg2 development are:
|
||||
|
||||
* Conformance - libmpeg2 is able to decode all mpeg streams that
|
||||
conform to certain restrictions: "constrained parameters" for
|
||||
mpeg-1, and "main profile" for mpeg-2. In practice, this is
|
||||
what most people are using. For streams that follow these
|
||||
restrictions, we believe libmpeg2 is 100% conformant to the
|
||||
mpeg standards - and we have a pretty extensive test suite to
|
||||
check this.
|
||||
|
||||
* Speed - there has been huge efforts there, and we believe
|
||||
libmpeg2 is the fastest library around for what it
|
||||
does. Please tell us if you find a faster one ! With typical
|
||||
video streams as found on DVD's, and doing only decoding with
|
||||
no display, you should be able to get about 110 fps on a
|
||||
PIII/666, or 150 fps on an Athlon/950. This is less than 20
|
||||
cycles per output pixel. In a real player program, the display
|
||||
routines will probably take as much time as the actual
|
||||
decoding !
|
||||
|
||||
* Portability - most of the code is written in C, and when we
|
||||
use platform-specific optimizations (typically assembly
|
||||
routines, currently used for the motion compensation and the
|
||||
inverse cosine transform stages) we always have a generic C
|
||||
routine to fall back on. This should be portable to all
|
||||
architectures - at least we have heard reports from people
|
||||
running this code on x86, ppc, sparc, arm and
|
||||
sh4. Assembly-optimized implementations are available on x86
|
||||
(MMX) and ppc (altivec) architectures. Ultrasparc (VIS) is
|
||||
probably the next on the list - we'll see.
|
||||
|
||||
* Reuseability - we do not want libmpeg2 to include any
|
||||
project-specific code, but it should still include enough
|
||||
features to be used by very diverse projects. We are only
|
||||
starting to get there - the best way to help here is to give
|
||||
us some feedback !
|
||||
|
||||
The project homepage is at http://libmpeg2.sourceforge.net/
|
||||
|
||||
|
||||
MPEG2DEC
|
||||
|
||||
mpeg2dec is a test program for libmpeg2. It decodes mpeg-1 and mpeg-2
|
||||
video streams, and also includes a demultiplexer for mpeg-1 and mpeg-2
|
||||
program streams. It is purposely kept simple : it does not include
|
||||
features like reading files from a DVD, CSS, fullscreen output,
|
||||
navigation, etc... The main purpose of mpeg2dec is to have a simple
|
||||
test bed for libmpeg2.
|
||||
|
||||
The libmpeg2 source code is always distributed in the mpeg2dec
|
||||
package, to make it easier for people to test it.
|
||||
|
||||
The basic usage is to just type "mpeg2dec file" where file is a
|
||||
demultiplexed mpeg video file.
|
||||
|
||||
The "-s" option must be used for multiplexed (audio and video) mpeg
|
||||
files using the "program stream" format. These files are usualy found
|
||||
on the internet or on unencrypted DVDs.
|
||||
|
||||
The "-t" option must be used for multiplexed (audio and video) mpeg
|
||||
files using the "transport stream" format. These files are usualy
|
||||
found in digital TV applications.
|
||||
|
||||
The "-o" option is used to select a given output module - for example
|
||||
to redirect the output to a file. This is also used for performance
|
||||
testing and conformance testing.
|
||||
|
||||
The "-c" option is used to disable all optimizations.
|
||||
|
||||
|
||||
OTHER PROJECTS USING LIBMPEG2
|
||||
|
||||
libmpeg2 is being used by various other projects, including:
|
||||
|
||||
* xine (http://xine.sourceforge.net/) - started as a simple
|
||||
mpeg-2 audio and video decoder, but it since became a
|
||||
full-featured DVD and video media player.
|
||||
|
||||
* VideoLAN (http://www.videolan.org/) - video streaming over an
|
||||
ethernet network, can also be used as a standalone player.
|
||||
|
||||
* MPlayer (http://www.MPlayerHQ.hu) - another good player, it is
|
||||
also very robust against damaged streams.
|
||||
|
||||
* movietime (http://movietime.sourceforge.net/) - still quite
|
||||
young, but it looks very promising !
|
||||
|
||||
* mpeg2decX (http://homepage1.nifty.com/~toku/software_en.html) -
|
||||
a graphical interface for mpeg2dec for macintosh osX.
|
||||
|
||||
* TCVP (http://tcvp.sf.net) - video and music player for unix.
|
||||
|
||||
* drip (http://drip.sourceforge.net/) - a DVD to DIVX transcoder.
|
||||
|
||||
* PoMP
|
||||
(http://www.dmclab.hanyang.ac.kr/research/project/PoDS/PoDS_sw.htm) -
|
||||
a research player optimized to minimize disk power consumption.
|
||||
|
||||
* OMS (http://www.linuxvideo.org/oms/)
|
||||
|
||||
* XMPS (http://xmps.sourceforge.net/)
|
||||
|
||||
* GStreamer (http://www.gstreamer.net/) - a framework for
|
||||
streaming media; it has an mpeg2 decoding plugin based on
|
||||
libmpeg2.
|
||||
|
||||
* mpeglib (http://mpeglib.sourceforge.net/) - a video decoding
|
||||
library that usess libmpeg2 when decoding mpeg streams.
|
||||
|
||||
* daphne (http://daphne.rulecity.com/) - a laserdisc arcade game
|
||||
simulator.
|
||||
|
||||
* GOPchop (http://outflux.net/unix/software/GOPchop/) - a
|
||||
GOP-accurate editor for MPEG2 streams.
|
||||
|
||||
If you use libmpeg2 in another project, let us know !
|
||||
|
||||
|
||||
TASKS
|
||||
|
||||
There are several places where we could easily use some help:
|
||||
|
||||
* Documentation: libmpeg2 still has no documentation. Every
|
||||
project using it has had to figure things out by looking at
|
||||
the header files, at the mpeg2dec sample application, and by
|
||||
asking questions. Writing down a nice documentation would make
|
||||
the code more easily reuseable.
|
||||
|
||||
* Testing: If you find any stream that does not decode right
|
||||
with libmpeg2, let us know ! The best thing would be to mail
|
||||
to the libmpeg2-devel mailing list. Also, it would be nice to
|
||||
build a stress test so we can make sure libmpeg2 never crashes
|
||||
on bad streams.
|
||||
|
||||
* Coding: There is a small TODO list in the mpeg2dec package,
|
||||
you can have a look there ! Most items are pretty terse
|
||||
though.
|
||||
|
||||
* Porting: If you're porting to a new architecture, you might
|
||||
want to experiment with the compile flags defined in
|
||||
configure.in . When you figure out whats fastest on your
|
||||
platform, send us a patch !
|
||||
|
||||
* Assembly optimizations: We only have x86 and altivec
|
||||
optimizations yet, it would be worthwhile writing routines for
|
||||
other architectures, especially those that have SIMD
|
||||
instruction set extensions ! Also the yuv2rgb x86 routines
|
||||
could probably be optimized a lot.
|
||||
|
||||
|
||||
CVS SNAPSHOTS
|
||||
|
||||
A daily snapshot is created using "make distcheck" every night and
|
||||
uploaded to http://libmpeg2.sourceforge.net/files/mpeg2dec-snapshot.tar.gz .
|
||||
It is easier to use than the CVS repository, because you do not need
|
||||
to have the right versions of automake, autoconf and libtool
|
||||
installed. It might be convenient when working on a libmpeg2 port for
|
||||
example.
|
||||
|
||||
|
||||
CVS REPOSITORY
|
||||
|
||||
The latest libmpeg2 and mpeg2dec source code can always be found by
|
||||
anonymous CVS:
|
||||
|
||||
# export CVSROOT=:pserver:anonymous@cvs.libmpeg2.sourceforge.net:/cvsroot/libmpeg2
|
||||
# cvs login (Just press Return when prompted for a password)
|
||||
# cvs checkout mpeg2dec
|
||||
|
||||
You can also browse the latest changes online at
|
||||
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/libmpeg2/mpeg2dec/
|
||||
|
||||
The other CVS modules are mpeg2dec-streams for the test suite, and
|
||||
mpeg2dec-livid for the CVS history of the project while it was still
|
||||
hosted on the linuxvideo.org servers.
|
||||
|
||||
|
||||
MAILING LISTS
|
||||
|
||||
See the subscription information at http://libmpeg2.sourceforge.net/lists.html
|
||||
|
||||
libmpeg2-devel
|
||||
|
||||
This is the main mailing list for technical discussion about
|
||||
libmpeg2. Anyone wanting to work on libmpeg2, or maybe just stay
|
||||
informed about the development process, should probably subscribe to
|
||||
this list.
|
||||
|
||||
libmpeg2-checkins
|
||||
|
||||
All libmpeg2 checkins are announced there. This is a good way to keep
|
||||
track of what goes into CVS.
|
||||
|
||||
libmpeg2-announce
|
||||
|
||||
This is a very low traffic mailing list, only for announcements of new
|
||||
versions of libmpeg2. Only project administrators can post there.
|
|
@ -1,44 +0,0 @@
|
|||
Library: libmpeg2 from mpeg2dec-0.4.0b (Released 2004-01-21)
|
||||
Imported: 2006-08-06 by Dave Chapman
|
||||
|
||||
|
||||
This directory contains a local version of libmpeg2 imported into
|
||||
Rockbox for MPEG video decoding.
|
||||
|
||||
|
||||
LICENSING INFORMATION
|
||||
|
||||
mpeg2dec and libmpeg2 are licensed under Version 2 of the GNU General
|
||||
Public License.
|
||||
|
||||
|
||||
IMPORT DETAILS
|
||||
|
||||
The following files were imported from the mpeg2dec-0.4.0b
|
||||
distribution. Minor changes were made to enable compilation in
|
||||
Rockbox and TABs were replaced by spaces to comply with the Rockbox
|
||||
coding guidelines.
|
||||
|
||||
AUTHORS
|
||||
README
|
||||
SOURCES
|
||||
attributes.h
|
||||
cpu_accel.c
|
||||
cpu_state.c
|
||||
decode.c
|
||||
header.c
|
||||
idct.c
|
||||
motion_comp.c
|
||||
mpeg2.h
|
||||
mpeg2_internal.h
|
||||
slice.c
|
||||
video_out.h
|
||||
vlc.h
|
||||
|
||||
The following files are new, but based on code in mpeg2dec.
|
||||
|
||||
Makefile
|
||||
mpegplayer.c
|
||||
video_out_rockbox.c
|
||||
mpeg2dec_config.h
|
||||
alloc.c
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* $Id$
|
||||
* libmpeg2 sync history:
|
||||
* 2008-07-01 - CVS revision 1.5
|
||||
*/
|
||||
|
||||
/* 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
|
||||
|
||||
#if defined(LIKELY) && defined (UNLIKELY)
|
||||
#define likely(x) LIKELY(x)
|
||||
#define unlikely(x) UNLIKELY(x)
|
||||
#else
|
||||
#define likely(x) (x)
|
||||
#define unlikely(x) (x)
|
||||
#endif
|
||||
|
|
@ -1,527 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* $Id$
|
||||
* libmpeg2 sync history:
|
||||
* 2008-07-01 - CVS revision 1.114
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
#include "mpeg2dec_config.h"
|
||||
|
||||
#include "mpeg2.h"
|
||||
#include "attributes.h"
|
||||
#include "mpeg2_internal.h"
|
||||
|
||||
#define BUFFER_SIZE (1194 * 1024)
|
||||
|
||||
#if defined(CPU_COLDFIRE) || (defined(CPU_ARM) && ARM_ARCH >= 6)
|
||||
/* twice as large as on other targets because coldfire uses
|
||||
* a secondary, transposed buffer for optimisation */
|
||||
static int16_t static_dct_block[128] IBSS_ATTR ATTR_ALIGN(16);
|
||||
#define DCT_BLOCKSIZE (128 * sizeof (int16_t))
|
||||
#else
|
||||
static int16_t static_dct_block[64] IBSS_ATTR ATTR_ALIGN(16);
|
||||
#define DCT_BLOCKSIZE (64 * sizeof (int16_t))
|
||||
#endif
|
||||
|
||||
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;
|
||||
uint32_t shift;
|
||||
uint8_t * limit;
|
||||
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;
|
||||
uint32_t shift;
|
||||
uint8_t * chunk_ptr;
|
||||
uint8_t * limit;
|
||||
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_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 STATE_INTERNAL_NORETURN;
|
||||
}
|
||||
|
||||
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 == 0xb7) ?
|
||||
mpeg2_header_end(mpeg2dec) : mpeg2_parse_header(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 (state > STATE_INTERNAL_NORETURN)
|
||||
return state;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
while ((unsigned) (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_slice (&mpeg2dec->decoder, mpeg2dec->code,
|
||||
mpeg2dec->chunk_start);
|
||||
mpeg2dec->code = mpeg2dec->buf_start[-1];
|
||||
mpeg2dec->chunk_ptr = mpeg2dec->chunk_start;
|
||||
}
|
||||
|
||||
if ((unsigned) (mpeg2dec->code - 1) >= 0xb0 - 1)
|
||||
break;
|
||||
|
||||
if (seek_chunk (mpeg2dec) == STATE_BUFFER)
|
||||
return STATE_BUFFER;
|
||||
}
|
||||
|
||||
mpeg2dec->action = mpeg2_seek_header;
|
||||
|
||||
switch (mpeg2dec->code)
|
||||
{
|
||||
case 0x00:
|
||||
return mpeg2dec->state;
|
||||
case 0xb3:
|
||||
case 0xb7:
|
||||
case 0xb8:
|
||||
return (mpeg2dec->state == STATE_SLICE) ? STATE_SLICE : STATE_INVALID;
|
||||
default:
|
||||
mpeg2dec->action = seek_chunk;
|
||||
return STATE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
mpeg2_state_t mpeg2_parse_header (mpeg2dec_t * mpeg2dec)
|
||||
{
|
||||
static int (* const process_header[9]) (mpeg2dec_t *) =
|
||||
{
|
||||
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):
|
||||
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);
|
||||
break;
|
||||
case RECEIVED (0x01, STATE_PICTURE):
|
||||
case RECEIVED (0x01, STATE_PICTURE_2ND):
|
||||
mpeg2_header_picture_finalize (mpeg2dec);
|
||||
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,
|
||||
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,
|
||||
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[MPEG2_COMPONENTS], 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];
|
||||
#if MPEG2_COLOR
|
||||
fbuf->buf[1] = buf[1];
|
||||
fbuf->buf[2] = buf[2];
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
mpeg2_idct_init ();
|
||||
|
||||
mpeg2dec = (mpeg2dec_t *)mpeg2_bufalloc(sizeof (mpeg2dec_t),
|
||||
MPEG2_ALLOC_MPEG2DEC);
|
||||
if (mpeg2dec == NULL)
|
||||
return NULL;
|
||||
|
||||
mpeg2dec->decoder.DCTblock = static_dct_block;
|
||||
|
||||
rb->memset (mpeg2dec->decoder.DCTblock, 0, DCT_BLOCKSIZE);
|
||||
|
||||
DEBUGF("DCTblock: %p\n", mpeg2dec->decoder.DCTblock);
|
||||
|
||||
mpeg2dec->chunk_buffer = (uint8_t *)mpeg2_bufalloc(BUFFER_SIZE + 4,
|
||||
MPEG2_ALLOC_CHUNK);
|
||||
|
||||
mpeg2dec->sequence.width = (unsigned)-1;
|
||||
mpeg2_reset (mpeg2dec, 1);
|
||||
|
||||
return mpeg2dec;
|
||||
}
|
||||
|
||||
void mpeg2_close (mpeg2dec_t * mpeg2dec)
|
||||
{
|
||||
mpeg2_header_state_init (mpeg2dec);
|
||||
#if 0
|
||||
/* These are dedicated buffers in rockbox */
|
||||
mpeg2_free (mpeg2dec->chunk_buffer);
|
||||
mpeg2_free (mpeg2dec);
|
||||
#endif
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,274 +0,0 @@
|
|||
/*
|
||||
* idct.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
|
||||
*
|
||||
* $Id$
|
||||
* libmpeg2 sync history:
|
||||
* 2008-07-01 - CVS revision 1.36
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
#include "mpeg2dec_config.h"
|
||||
|
||||
#include "mpeg2.h"
|
||||
#include "attributes.h"
|
||||
#include "mpeg2_internal.h"
|
||||
|
||||
#if defined(CPU_COLDFIRE) || defined (CPU_ARM)
|
||||
#define IDCT_ASM
|
||||
#endif
|
||||
|
||||
#ifndef IDCT_ASM
|
||||
|
||||
#define W1 2841 /* 2048 * sqrt (2) * cos (1 * pi / 16) */
|
||||
#define W2 2676 /* 2048 * sqrt (2) * cos (2 * pi / 16) */
|
||||
#define W3 2408 /* 2048 * sqrt (2) * cos (3 * pi / 16) */
|
||||
#define W5 1609 /* 2048 * sqrt (2) * cos (5 * pi / 16) */
|
||||
#define W6 1108 /* 2048 * sqrt (2) * cos (6 * pi / 16) */
|
||||
#define W7 565 /* 2048 * sqrt (2) * cos (7 * pi / 16) */
|
||||
|
||||
/*
|
||||
* In legal streams, the IDCT output should be between -384 and +384.
|
||||
* In corrupted streams, it is possible to force the IDCT output to go
|
||||
* to +-3826 - this is the worst case for a column IDCT where the
|
||||
* column inputs are 16-bit values.
|
||||
*/
|
||||
#define CLIP(i) \
|
||||
({ typeof (i) _i = (i); \
|
||||
if ((_i & 0xff) != _i) \
|
||||
_i = ~(_i >> (8*sizeof(_i) - 1)); \
|
||||
_i; })
|
||||
|
||||
#if 0
|
||||
#define BUTTERFLY(t0,t1,W0,W1,d0,d1) \
|
||||
do { \
|
||||
t0 = W0 * d0 + W1 * d1; \
|
||||
t1 = W0 * d1 - W1 * d0; \
|
||||
} while (0)
|
||||
#else
|
||||
#define BUTTERFLY(t0,t1,W0,W1,d0,d1) \
|
||||
do { \
|
||||
int tmp = W0 * (d0 + d1); \
|
||||
t0 = tmp + (W1 - W0) * d1; \
|
||||
t1 = tmp - (W1 + W0) * d0; \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static inline void idct_row (int16_t * const block)
|
||||
{
|
||||
int d0, d1, d2, d3;
|
||||
int a0, a1, a2, a3, b0, b1, b2, b3;
|
||||
int t0, t1, t2, t3;
|
||||
|
||||
/* shortcut */
|
||||
if (likely (!(block[1] | ((int32_t *)block)[1] | ((int32_t *)block)[2] |
|
||||
((int32_t *)block)[3])))
|
||||
{
|
||||
uint32_t tmp = (uint16_t) (block[0] >> 1);
|
||||
tmp |= tmp << 16;
|
||||
((int32_t *)block)[0] = tmp;
|
||||
((int32_t *)block)[1] = tmp;
|
||||
((int32_t *)block)[2] = tmp;
|
||||
((int32_t *)block)[3] = tmp;
|
||||
return;
|
||||
}
|
||||
|
||||
d0 = (block[0] << 11) + 2048;
|
||||
d1 = block[1];
|
||||
d2 = block[2] << 11;
|
||||
d3 = block[3];
|
||||
t0 = d0 + d2;
|
||||
t1 = d0 - d2;
|
||||
BUTTERFLY (t2, t3, W6, W2, d3, d1);
|
||||
a0 = t0 + t2;
|
||||
a1 = t1 + t3;
|
||||
a2 = t1 - t3;
|
||||
a3 = t0 - t2;
|
||||
|
||||
d0 = block[4];
|
||||
d1 = block[5];
|
||||
d2 = block[6];
|
||||
d3 = block[7];
|
||||
BUTTERFLY (t0, t1, W7, W1, d3, d0);
|
||||
BUTTERFLY (t2, t3, W3, W5, d1, d2);
|
||||
b0 = t0 + t2;
|
||||
b3 = t1 + t3;
|
||||
t0 -= t2;
|
||||
t1 -= t3;
|
||||
b1 = ((t0 + t1) >> 8) * 181;
|
||||
b2 = ((t0 - t1) >> 8) * 181;
|
||||
|
||||
block[0] = (a0 + b0) >> 12;
|
||||
block[1] = (a1 + b1) >> 12;
|
||||
block[2] = (a2 + b2) >> 12;
|
||||
block[3] = (a3 + b3) >> 12;
|
||||
block[4] = (a3 - b3) >> 12;
|
||||
block[5] = (a2 - b2) >> 12;
|
||||
block[6] = (a1 - b1) >> 12;
|
||||
block[7] = (a0 - b0) >> 12;
|
||||
}
|
||||
|
||||
static inline void idct_col (int16_t * const block)
|
||||
{
|
||||
int d0, d1, d2, d3;
|
||||
int a0, a1, a2, a3, b0, b1, b2, b3;
|
||||
int t0, t1, t2, t3;
|
||||
|
||||
d0 = (block[8*0] << 11) + 65536;
|
||||
d1 = block[8*1];
|
||||
d2 = block[8*2] << 11;
|
||||
d3 = block[8*3];
|
||||
t0 = d0 + d2;
|
||||
t1 = d0 - d2;
|
||||
BUTTERFLY (t2, t3, W6, W2, d3, d1);
|
||||
a0 = t0 + t2;
|
||||
a1 = t1 + t3;
|
||||
a2 = t1 - t3;
|
||||
a3 = t0 - t2;
|
||||
|
||||
d0 = block[8*4];
|
||||
d1 = block[8*5];
|
||||
d2 = block[8*6];
|
||||
d3 = block[8*7];
|
||||
BUTTERFLY (t0, t1, W7, W1, d3, d0);
|
||||
BUTTERFLY (t2, t3, W3, W5, d1, d2);
|
||||
b0 = t0 + t2;
|
||||
b3 = t1 + t3;
|
||||
t0 -= t2;
|
||||
t1 -= t3;
|
||||
b1 = ((t0 + t1) >> 8) * 181;
|
||||
b2 = ((t0 - t1) >> 8) * 181;
|
||||
|
||||
block[8*0] = (a0 + b0) >> 17;
|
||||
block[8*1] = (a1 + b1) >> 17;
|
||||
block[8*2] = (a2 + b2) >> 17;
|
||||
block[8*3] = (a3 + b3) >> 17;
|
||||
block[8*4] = (a3 - b3) >> 17;
|
||||
block[8*5] = (a2 - b2) >> 17;
|
||||
block[8*6] = (a1 - b1) >> 17;
|
||||
block[8*7] = (a0 - b0) >> 17;
|
||||
}
|
||||
|
||||
void mpeg2_idct_copy (int16_t * block, uint8_t * dest,
|
||||
const int stride)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
idct_row (block + 8 * i);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
idct_col (block + i);
|
||||
|
||||
do
|
||||
{
|
||||
dest[0] = CLIP (block[0]);
|
||||
dest[1] = CLIP (block[1]);
|
||||
dest[2] = CLIP (block[2]);
|
||||
dest[3] = CLIP (block[3]);
|
||||
dest[4] = CLIP (block[4]);
|
||||
dest[5] = CLIP (block[5]);
|
||||
dest[6] = CLIP (block[6]);
|
||||
dest[7] = CLIP (block[7]);
|
||||
|
||||
((int32_t *)block)[0] = 0;
|
||||
((int32_t *)block)[1] = 0;
|
||||
((int32_t *)block)[2] = 0;
|
||||
((int32_t *)block)[3] = 0;
|
||||
|
||||
dest += stride;
|
||||
block += 8;
|
||||
}
|
||||
while (--i);
|
||||
}
|
||||
|
||||
void mpeg2_idct_add (const int last, int16_t * block,
|
||||
uint8_t * dest, const int stride)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (last != 129 || (block[0] & (7 << 4)) == (4 << 4))
|
||||
{
|
||||
for (i = 0; i < 8; i++)
|
||||
idct_row (block + 8 * i);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
idct_col (block + i);
|
||||
|
||||
do
|
||||
{
|
||||
dest[0] = CLIP (block[0] + dest[0]);
|
||||
dest[1] = CLIP (block[1] + dest[1]);
|
||||
dest[2] = CLIP (block[2] + dest[2]);
|
||||
dest[3] = CLIP (block[3] + dest[3]);
|
||||
dest[4] = CLIP (block[4] + dest[4]);
|
||||
dest[5] = CLIP (block[5] + dest[5]);
|
||||
dest[6] = CLIP (block[6] + dest[6]);
|
||||
dest[7] = CLIP (block[7] + dest[7]);
|
||||
|
||||
((int32_t *)block)[0] = 0;
|
||||
((int32_t *)block)[1] = 0;
|
||||
((int32_t *)block)[2] = 0;
|
||||
((int32_t *)block)[3] = 0;
|
||||
|
||||
dest += stride;
|
||||
block += 8;
|
||||
}
|
||||
while (--i);
|
||||
}
|
||||
else
|
||||
{
|
||||
int DC = (block[0] + 64) >> 7;
|
||||
block[0] = block[63] = 0;
|
||||
i = 8;
|
||||
|
||||
do
|
||||
{
|
||||
dest[0] = CLIP (DC + dest[0]);
|
||||
dest[1] = CLIP (DC + dest[1]);
|
||||
dest[2] = CLIP (DC + dest[2]);
|
||||
dest[3] = CLIP (DC + dest[3]);
|
||||
dest[4] = CLIP (DC + dest[4]);
|
||||
dest[5] = CLIP (DC + dest[5]);
|
||||
dest[6] = CLIP (DC + dest[6]);
|
||||
dest[7] = CLIP (DC + dest[7]);
|
||||
dest += stride;
|
||||
}
|
||||
while (--i);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* IDCT_ASM */
|
||||
|
||||
void mpeg2_idct_init (void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
j = default_mpeg2_scan_norm[i];
|
||||
mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
|
||||
|
||||
j = default_mpeg2_scan_alt[i];
|
||||
mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2);
|
||||
}
|
||||
}
|
|
@ -1,443 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 by Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
.global mpeg2_idct_copy
|
||||
.type mpeg2_idct_copy, %function
|
||||
.global mpeg2_idct_add
|
||||
.type mpeg2_idct_add, %function
|
||||
|
||||
|
||||
/* Custom calling convention:
|
||||
* r0 contains block pointer and is non-volatile
|
||||
* all non-volatile c context saved and restored on its behalf
|
||||
*/
|
||||
.idct:
|
||||
add r12, r0, #128
|
||||
1:
|
||||
ldrsh r1, [r0, #0] /* d0 */
|
||||
ldrsh r2, [r0, #2] /* d1 */
|
||||
ldrsh r3, [r0, #4] /* d2 */
|
||||
ldrsh r4, [r0, #6] /* d3 */
|
||||
ldrsh r5, [r0, #8] /* d0 */
|
||||
ldrsh r6, [r0, #10] /* d1 */
|
||||
ldrsh r7, [r0, #12] /* d2 */
|
||||
ldrsh r8, [r0, #14] /* d3 */
|
||||
orrs r9, r2, r3
|
||||
orreqs r9, r4, r5
|
||||
orreqs r9, r6, r7
|
||||
cmpeq r8, #0
|
||||
bne 2f
|
||||
mov r1, r1, asl #15
|
||||
bic r1, r1, #0x8000
|
||||
orr r1, r1, r1, lsr #16
|
||||
str r1, [r0], #4
|
||||
str r1, [r0], #4
|
||||
str r1, [r0], #4
|
||||
str r1, [r0], #4
|
||||
cmp r0, r12
|
||||
blo 1b
|
||||
b 3f
|
||||
2:
|
||||
mov r1, r1, asl #11 /* r1 = d0 = (block[0] << 11) + 2048 */
|
||||
add r1, r1, #2048
|
||||
add r1, r1, r3, asl #11 /* r1 = t0 = d0 + (block[2] << 11) */
|
||||
sub r3, r1, r3, asl #12 /* r3 = t1 = d0 - (block[2] << 11) */
|
||||
|
||||
add r9, r2, r4 /* r9 = tmp = (d1+d3)*(1108/4) */
|
||||
add r10, r9, r9, asl #2
|
||||
add r10, r10, r9, asl #4
|
||||
add r9, r10, r9, asl #8
|
||||
|
||||
add r10, r2, r2, asl #4 /* r2 = t2 = tmp + (d1*(1568/32)*8) */
|
||||
add r2, r10, r2, asl #5
|
||||
add r2, r9, r2, asl #3
|
||||
|
||||
add r10, r4, r4, asl #2 /* r4 = t3 = tmp - (d3*(3784/8)*2) */
|
||||
rsb r10, r10, r4, asl #6
|
||||
add r4, r4, r10, asl #3
|
||||
sub r4, r9, r4, asl #1
|
||||
/* t2 & t3 are 1/4 final value here */
|
||||
add r1, r1, r2, asl #2 /* r1 = a0 = t0 + t2 */
|
||||
sub r2, r1, r2, asl #3 /* r2 = a3 = t0 - t2 */
|
||||
add r3, r3, r4, asl #2 /* r3 = a1 = t1 + t3 */
|
||||
sub r4, r3, r4, asl #3 /* r4 = a2 = t1 - t3 */
|
||||
|
||||
add r9, r8, r5 /* r9 = tmp = 565*(d3 + d0) */
|
||||
add r10, r9, r9, asl #4
|
||||
add r10, r10, r10, asl #5
|
||||
add r9, r10, r9, asl #2
|
||||
|
||||
add r10, r5, r5, asl #4 /* r5 = t0 = tmp + (((2276/4)*d0)*4) */
|
||||
add r10, r10, r10, asl #5
|
||||
add r5, r10, r5, asl #3
|
||||
add r5, r9, r5, asl #2
|
||||
|
||||
add r10, r8, r8, asl #2 /* r8 = t1 = tmp - (((3406/2)*d3)*2) */
|
||||
add r10, r10, r10, asl #4
|
||||
add r10, r10, r8, asl #7
|
||||
rsb r8, r8, r10, asl #3
|
||||
sub r8, r9, r8, asl #1
|
||||
|
||||
add r9, r6, r7 /* r9 = tmp = (2408/8)*(d1 + d2) */
|
||||
add r10, r9, r9, asl #3
|
||||
add r10, r10, r10, asl #5
|
||||
add r9, r10, r9, asl #2
|
||||
|
||||
add r10, r7, r7, asl #3 /* r7 = t2 = (tmp*8) - 799*d2 */
|
||||
add r10, r10, r7, asl #4
|
||||
rsb r7, r7, r10, asl #5
|
||||
rsb r7, r7, r9, asl #3
|
||||
|
||||
sub r10, r6, r6, asl #4 /* r6 = t3 = (tmp*8) - 4017*d1 */
|
||||
sub r10, r10, r6, asl #6
|
||||
add r10, r10, r6, asl #12
|
||||
add r6, r10, r6
|
||||
rsb r6, r6, r9, asl #3
|
||||
/* t0 = r5, t1 = r8, t2 = r7, t3 = r6*/
|
||||
add r9, r5, r7 /* r9 = b0 = t0 + t2 */
|
||||
add r10, r8, r6 /* r10 = b3 = t1 + t3 */
|
||||
sub r5, r5, r7 /* t0 -= t2 */
|
||||
sub r8, r8, r6 /* t1 -= t3 */
|
||||
add r6, r5, r8 /* r6 = t0 + t1 */
|
||||
sub r7, r5, r8 /* r7 = t0 - t1 */
|
||||
|
||||
add r11, r6, r6, asr #2 /* r6 = b1 = r6*(181/128) */
|
||||
add r11, r11, r11, asr #5
|
||||
add r6, r11, r6, asr #3
|
||||
add r11, r7, r7, asr #2 /* r7 = b2 = r7*(181/128) */
|
||||
add r11, r11, r11, asr #5
|
||||
add r7, r11, r7, asr #3
|
||||
/* r1 = a0, r3 = a1, r4 = a2, r2 = a3 */
|
||||
/* r9 = b0, r6 = b1*2, r7 = b2*2, r10 = b3 */
|
||||
add r5, r1, r9 /* block[0] = (a0 + b0) >> 12 */
|
||||
mov r5, r5, asr #12
|
||||
strh r5, [r0], #2
|
||||
add r8, r3, r6, asr #1 /* block[1] = (a1 + b1) >> 12 */
|
||||
mov r8, r8, asr #12
|
||||
strh r8, [r0], #2
|
||||
add r5, r4, r7, asr #1 /* block[2] = (a2 + b2) >> 12 */
|
||||
mov r5, r5, asr #12
|
||||
strh r5, [r0], #2
|
||||
add r8, r2, r10 /* block[3] = (a3 + b3) >> 12 */
|
||||
mov r8, r8, asr #12
|
||||
strh r8, [r0], #2
|
||||
sub r5, r2, r10 /* block[4] = (a3 - b3) >> 12 */
|
||||
mov r5, r5, asr #12
|
||||
strh r5, [r0], #2
|
||||
sub r8, r4, r7, asr #1 /* block[5] = (a2 - b2) >> 12 */
|
||||
mov r8, r8, asr #12
|
||||
strh r8, [r0], #2
|
||||
sub r5, r3, r6, asr #1 /* block[6] = (a1 - b1) >> 12 */
|
||||
mov r5, r5, asr #12
|
||||
strh r5, [r0], #2
|
||||
sub r8, r1, r9 /* block[7] = (a0 - b0) >> 12 */
|
||||
mov r8, r8, asr #12
|
||||
strh r8, [r0], #2
|
||||
cmp r0, r12
|
||||
blo 1b
|
||||
3:
|
||||
sub r0, r0, #128
|
||||
add r12, r0, #16
|
||||
4:
|
||||
ldrsh r1, [r0, #0*8] /* d0 */
|
||||
ldrsh r2, [r0, #2*8] /* d1 */
|
||||
ldrsh r3, [r0, #4*8] /* d2 */
|
||||
ldrsh r4, [r0, #6*8] /* d3 */
|
||||
ldrsh r5, [r0, #8*8] /* d0 */
|
||||
ldrsh r6, [r0, #10*8] /* d1 */
|
||||
ldrsh r7, [r0, #12*8] /* d2 */
|
||||
ldrsh r8, [r0, #14*8] /* d3 */
|
||||
|
||||
mov r1, r1, asl #11 /* r1 = d0 = (block[0] << 11) + 2048 */
|
||||
add r1, r1, #65536
|
||||
add r1, r1, r3, asl #11 /* r1 = t0 = d0 + d2:(block[2] << 11) */
|
||||
sub r3, r1, r3, asl #12 /* r3 = t1 = d0 - d2:(block[2] << 11) */
|
||||
|
||||
add r9, r2, r4 /* r9 = tmp = (d1+d3)*(1108/4) */
|
||||
add r10, r9, r9, asl #2
|
||||
add r10, r10, r9, asl #4
|
||||
add r9, r10, r9, asl #8
|
||||
|
||||
add r11, r2, r2, asl #4 /* r2 = t2 = tmp + (d1*(1568/32)*8) */
|
||||
add r2, r11, r2, asl #5
|
||||
add r2, r9, r2, asl #3
|
||||
|
||||
add r10, r4, r4, asl #2 /* r4 = t3 = tmp - (d3*(3784/8)*2) */
|
||||
rsb r10, r10, r4, asl #6
|
||||
add r4, r4, r10, asl #3
|
||||
sub r4, r9, r4, asl #1
|
||||
/* t2 & t3 are 1/4 final value here */
|
||||
add r1, r1, r2, asl #2 /* r1 = a0 = t0 + t2 */
|
||||
sub r2, r1, r2, asl #3 /* r2 = a3 = t0 - t2 */
|
||||
add r3, r3, r4, asl #2 /* r3 = a1 = t1 + t3 */
|
||||
sub r4, r3, r4, asl #3 /* r4 = a2 = t1 - t3 */
|
||||
|
||||
add r9, r8, r5 /* r9 = tmp = 565*(d3 + d0) */
|
||||
add r10, r9, r9, asl #4
|
||||
add r10, r10, r10, asl #5
|
||||
add r9, r10, r9, asl #2
|
||||
|
||||
add r10, r5, r5, asl #4 /* r5 = t0 = tmp + (((2276/4)*d0)*4) */
|
||||
add r10, r10, r10, asl #5
|
||||
add r5, r10, r5, asl #3
|
||||
add r5, r9, r5, asl #2
|
||||
|
||||
add r10, r8, r8, asl #2 /* r8 = t1 = tmp - (((3406/2)*d3)*2) */
|
||||
add r10, r10, r10, asl #4
|
||||
add r10, r10, r8, asl #7
|
||||
rsb r8, r8, r10, asl #3
|
||||
sub r8, r9, r8, asl #1
|
||||
|
||||
add r9, r6, r7 /* r9 = tmp = (2408/8)*(d1 + d2) */
|
||||
add r10, r9, r9, asl #3
|
||||
add r10, r10, r10, asl #5
|
||||
add r9, r10, r9, asl #2
|
||||
|
||||
add r10, r7, r7, asl #3 /* r7 = t2 = (tmp*8) - 799*d2 */
|
||||
add r10, r10, r7, asl #4
|
||||
rsb r7, r7, r10, asl #5
|
||||
rsb r7, r7, r9, asl #3
|
||||
|
||||
sub r10, r6, r6, asl #4 /* r6 = t3 = (tmp*8) - 4017*d1 */
|
||||
sub r10, r10, r6, asl #6
|
||||
add r10, r10, r6, asl #12
|
||||
add r6, r10, r6
|
||||
rsb r6, r6, r9, asl #3
|
||||
/* t0=r5, t1=r8, t2=r7, t3=r6*/
|
||||
add r9, r5, r7 /* r9 = b0 = t0 + t2 */
|
||||
add r10, r8, r6 /* r10 = b3 = t1 + t3 */
|
||||
sub r5, r5, r7 /* t0 -= t2 */
|
||||
sub r8, r8, r6 /* t1 -= t3 */
|
||||
add r6, r5, r8 /* r6 = t0 + t1 */
|
||||
sub r7, r5, r8 /* r7 = t0 - t1 */
|
||||
|
||||
add r11, r6, r6, asr #2 /* r6 = b1 = r5*(181/128) */
|
||||
add r11, r11, r11, asr #5
|
||||
add r6, r11, r6, asr #3
|
||||
add r11, r7, r7, asr #2 /* r7 = b2 = r6*(181/128) */
|
||||
add r11, r11, r11, asr #5
|
||||
add r7, r11, r7, asr #3
|
||||
/* r1 = a0, r3 = a1, r4 = a2, r2 = a3 */
|
||||
/* r9 = b0, r6 = b1*2, r7 = b2*2, r10 = b3 */
|
||||
add r5, r1, r9 /* block[0] = (a0 + b0) >> 17 */
|
||||
mov r5, r5, asr #17
|
||||
strh r5, [r0, #0*8]
|
||||
add r8, r3, r6, asr #1 /* block[1] = (a1 + b1) >> 17 */
|
||||
mov r8, r8, asr #17
|
||||
strh r8, [r0, #2*8]
|
||||
add r5, r4, r7, asr #1 /* block[2] = (a2 + b2) >> 17 */
|
||||
mov r5, r5, asr #17
|
||||
strh r5, [r0, #4*8]
|
||||
add r8, r2, r10 /* block[3] = (a3 + b3) >> 17 */
|
||||
mov r8, r8, asr #17
|
||||
strh r8, [r0, #6*8]
|
||||
sub r5, r2, r10 /* block[4] = (a3 - b3) >> 17 */
|
||||
mov r5, r5, asr #17
|
||||
strh r5, [r0, #8*8]
|
||||
sub r8, r4, r7, asr #1 /* block[5] = (a2 - b2) >> 17 */
|
||||
mov r8, r8, asr #17
|
||||
strh r8, [r0, #10*8]
|
||||
sub r5, r3, r6, asr #1 /* block[6] = (a1 - b1) >> 17 */
|
||||
mov r5, r5, asr #17
|
||||
strh r5, [r0, #12*8]
|
||||
sub r8, r1, r9 /* block[7] = (a0 - b0) >> 17 */
|
||||
mov r8, r8, asr #17
|
||||
strh r8, [r0, #14*8]
|
||||
add r0, r0, #2
|
||||
cmp r0, r12
|
||||
blo 4b
|
||||
sub r0, r0, #16
|
||||
bx lr
|
||||
|
||||
mpeg2_idct_copy:
|
||||
stmfd sp!, { r1-r2, r4-r11, lr }
|
||||
bl .idct
|
||||
ldmfd sp!, { r1-r2 }
|
||||
mov r11, #0
|
||||
add r12, r0, #128
|
||||
1:
|
||||
ldrsh r3, [r0, #0]
|
||||
ldrsh r4, [r0, #2]
|
||||
ldrsh r5, [r0, #4]
|
||||
ldrsh r6, [r0, #6]
|
||||
ldrsh r7, [r0, #8]
|
||||
ldrsh r8, [r0, #10]
|
||||
ldrsh r9, [r0, #12]
|
||||
ldrsh r10, [r0, #14]
|
||||
cmp r3, #255
|
||||
mvnhi r3, r3, asr #31
|
||||
strb r3, [r1, #0]
|
||||
str r11, [r0], #4
|
||||
cmp r4, #255
|
||||
mvnhi r4, r4, asr #31
|
||||
strb r4, [r1, #1]
|
||||
cmp r5, #255
|
||||
mvnhi r5, r5, asr #31
|
||||
strb r5, [r1, #2]
|
||||
str r11, [r0], #4
|
||||
cmp r6, #255
|
||||
mvnhi r6, r6, asr #31
|
||||
strb r6, [r1, #3]
|
||||
cmp r7, #255
|
||||
mvnhi r7, r7, asr #31
|
||||
strb r7, [r1, #4]
|
||||
str r11, [r0], #4
|
||||
cmp r8, #255
|
||||
mvnhi r8, r8, asr #31
|
||||
strb r8, [r1, #5]
|
||||
cmp r9, #255
|
||||
mvnhi r9, r9, asr #31
|
||||
strb r9, [r1, #6]
|
||||
str r11, [r0], #4
|
||||
cmp r10, #255
|
||||
mvnhi r10, r10, asr #31
|
||||
strb r10, [r1, #7]
|
||||
add r1, r1, r2
|
||||
cmp r0, r12
|
||||
blo 1b
|
||||
ldmpc regs=r4-r11
|
||||
|
||||
mpeg2_idct_add:
|
||||
cmp r0, #129
|
||||
mov r0, r1
|
||||
ldreqsh r1, [r0, #0]
|
||||
bne 1f
|
||||
and r1, r1, #0x70
|
||||
cmp r1, #0x40
|
||||
bne 3f
|
||||
1:
|
||||
stmfd sp!, { r2-r11, lr }
|
||||
bl .idct
|
||||
ldmfd sp!, { r1-r2 }
|
||||
mov r11, #0
|
||||
add r12, r0, #128
|
||||
2:
|
||||
ldrb r3, [r1, #0]
|
||||
ldrb r4, [r1, #1]
|
||||
ldrb r5, [r1, #2]
|
||||
ldrb r6, [r1, #3]
|
||||
ldrsh r7, [r0, #0]
|
||||
ldrsh r8, [r0, #2]
|
||||
ldrsh r9, [r0, #4]
|
||||
ldrsh r10, [r0, #6]
|
||||
add r7, r7, r3
|
||||
ldrb r3, [r1, #4]
|
||||
cmp r7, #255
|
||||
mvnhi r7, r7, asr #31
|
||||
strb r7, [r1, #0]
|
||||
ldrsh r7, [r0, #8]
|
||||
add r8, r8, r4
|
||||
ldrb r4, [r1, #5]
|
||||
cmp r8, #255
|
||||
mvnhi r8, r8, asr #31
|
||||
strb r8, [r1, #1]
|
||||
ldrsh r8, [r0, #10]
|
||||
add r9, r9, r5
|
||||
ldrb r5, [r1, #6]
|
||||
cmp r9, #255
|
||||
mvnhi r9, r9, asr #31
|
||||
strb r9, [r1, #2]
|
||||
ldrsh r9, [r0, #12]
|
||||
add r10, r10, r6
|
||||
ldrb r6, [r1, #7]
|
||||
cmp r10, #255
|
||||
mvnhi r10, r10, asr #31
|
||||
strb r10, [r1, #3]
|
||||
ldrsh r10, [r0, #14]
|
||||
str r11, [r0], #4
|
||||
add r7, r7, r3
|
||||
cmp r7, #255
|
||||
mvnhi r7, r7, asr #31
|
||||
strb r7, [r1, #4]
|
||||
str r11, [r0], #4
|
||||
add r8, r8, r4
|
||||
cmp r8, #255
|
||||
mvnhi r8, r8, asr #31
|
||||
strb r8, [r1, #5]
|
||||
str r11, [r0], #4
|
||||
add r9, r9, r5
|
||||
cmp r9, #255
|
||||
mvnhi r9, r9, asr #31
|
||||
strb r9, [r1, #6]
|
||||
add r10, r10, r6
|
||||
cmp r10, #255
|
||||
mvnhi r10, r10, asr #31
|
||||
strb r10, [r1, #7]
|
||||
str r11, [r0], #4
|
||||
add r1, r1, r2
|
||||
cmp r0, r12
|
||||
blo 2b
|
||||
ldmpc regs=r4-r11
|
||||
3:
|
||||
stmfd sp!, { r4-r5, lr }
|
||||
ldrsh r1, [r0, #0] /* r1 = block[0] */
|
||||
mov r4, #0
|
||||
strh r4, [r0, #0] /* block[0] = 0 */
|
||||
strh r4, [r0, #126] /* block[63] = 0 */
|
||||
add r1, r1, #64 /* r1 = DC << 7 */
|
||||
add r0, r2, r3, asl #3
|
||||
4:
|
||||
ldrb r4, [r2, #0]
|
||||
ldrb r5, [r2, #1]
|
||||
ldrb r12, [r2, #2]
|
||||
ldrb lr, [r2, #3]
|
||||
add r4, r4, r1, asr #7
|
||||
cmp r4, #255
|
||||
mvnhi r4, r4, asr #31
|
||||
strb r4, [r2, #0]
|
||||
add r5, r5, r1, asr #7
|
||||
cmp r5, #255
|
||||
mvnhi r5, r5, asr #31
|
||||
strb r5, [r2, #1]
|
||||
add r12, r12, r1, asr #7
|
||||
cmp r12, #255
|
||||
mvnhi r12, r12, asr #31
|
||||
strb r12, [r2, #2]
|
||||
add lr, lr, r1, asr #7
|
||||
cmp lr, #255
|
||||
mvnhi lr, lr, asr #31
|
||||
strb lr, [r2, #3]
|
||||
ldrb r4, [r2, #4]
|
||||
ldrb r5, [r2, #5]
|
||||
ldrb r12, [r2, #6]
|
||||
ldrb lr, [r2, #7]
|
||||
add r4, r4, r1, asr #7
|
||||
cmp r4, #255
|
||||
mvnhi r4, r4, asr #31
|
||||
strb r4, [r2, #4]
|
||||
add r5, r5, r1, asr #7
|
||||
cmp r5, #255
|
||||
mvnhi r5, r5, asr #31
|
||||
strb r5, [r2, #5]
|
||||
add r12, r12, r1, asr #7
|
||||
cmp r12, #255
|
||||
mvnhi r12, r12, asr #31
|
||||
strb r12, [r2, #6]
|
||||
add lr, lr, r1, asr #7
|
||||
cmp lr, #255
|
||||
mvnhi lr, lr, asr #31
|
||||
strb lr, [r2, #7]
|
||||
add r2, r2, r3
|
||||
cmp r2, r0
|
||||
blo 4b
|
||||
ldmpc regs=r4-r5
|
|
@ -1,297 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2009 by Jens Arnold
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
.global mpeg2_idct_copy
|
||||
.type mpeg2_idct_copy, %function
|
||||
.global mpeg2_idct_add
|
||||
.type mpeg2_idct_add, %function
|
||||
|
||||
/* Custom calling convention:
|
||||
* r0 contains block pointer and is non-volatile
|
||||
* all non-volatile c context saved and restored on its behalf
|
||||
*/
|
||||
.idct:
|
||||
str lr, [sp, #-4]! @ lr is used
|
||||
add r1, r0, #128 @ secondary, transposed temp buffer
|
||||
mov r14, #8 @ loop counter
|
||||
|
||||
.row_loop:
|
||||
ldmia r0!, {r2, r3, r10, r11} @ fetch f0, f2, f4, f6, f1, f3, f5, f7
|
||||
ldrd r4, L_W1357 @ load W1, W3, W5, W7
|
||||
|
||||
smuad r6, r4, r10 @ b0 = W1 * f1 + W3 * f3
|
||||
smultt r7, r5, r10 @ -b1 = W7 * f3
|
||||
smulbt r8, r4, r10 @ -b2 = W1 * f3
|
||||
|
||||
smusdx r9, r10, r5 @ b3 = f1 * W7 - f3 * W5
|
||||
smlabb r7, r4, r11, r7 @ -b1 += W1 * f5
|
||||
rsb r8, r8, #0 @ b2 = -b2
|
||||
smlabb r8, r5, r10, r8 @ b2 += W5 * f1
|
||||
|
||||
smlad r6, r5, r11, r6 @ b0 += W5 * f5 + W7 * f7
|
||||
smlabt r7, r5, r11, r7 @ -b1 += W5 * f7
|
||||
smlatb r8, r5, r11, r8 @ b2 += W7 * f5
|
||||
|
||||
smlsdx r9, r11, r4, r9 @ b3 += f5 * W3 - f7 * W1
|
||||
rsb r7, r7, #0 @ b1 = -b1
|
||||
smlatb r7, r4, r10, r7 @ b1 += W3 * f1
|
||||
smlatt r8, r4, r11, r8 @ b2 += W3 * f7
|
||||
|
||||
ldrd r4, L_W0246 @ load W0, W2, W4, W6
|
||||
add r2, r2, #1 @ f0 += 1
|
||||
|
||||
smulbb r10, r5, r3 @ a0' = W4 * f4
|
||||
smultt r12, r5, r3 @ a3' = W6 * f6
|
||||
smultt r3, r4, r3 @ -a2' = W2 * f6
|
||||
|
||||
rsb r11, r10, #0 @ a1' = -W4 * f4
|
||||
smlabb r10, r4, r2, r10 @ a0' += W0 * f0
|
||||
smlabb r11, r4, r2, r11 @ a1' += W0 * f0
|
||||
smlatt r12, r4, r2, r12 @ a3' += W2 * f2
|
||||
rsb r3, r3, #0 @ a2' = -a2'
|
||||
smlatt r3, r5, r2, r3 @ a2' += W6 * f2
|
||||
|
||||
add r10, r10, r12 @ a0 = a0' + a3'
|
||||
sub r12, r10, r12, lsl #1 @ a3 = a0 - 2 * a3'
|
||||
add r11, r11, r3 @ a1 = a1' + a2'
|
||||
sub r3, r11, r3, lsl #1 @ a2 = a1 - 2 * a2'
|
||||
|
||||
subs r14, r14, #1 @ decrease loop count
|
||||
|
||||
@ Special store order for making the column pass calculate columns in
|
||||
@ the order 0-2-1-3-4-6-5-7, allowing for uxtab16 use in later stages.
|
||||
sub r2, r10, r6 @ block[7] = (a0 - b0)
|
||||
mov r2, r2, asr #12 @ >> 12
|
||||
strh r2, [r1, #7*16]
|
||||
sub r2, r11, r7 @ block[6] = (a1 - b1)
|
||||
mov r2, r2, asr #12 @ >> 12
|
||||
strh r2, [r1, #5*16]
|
||||
sub r2, r3, r8 @ block[5] = (a2 - b2)
|
||||
mov r2, r2, asr #12 @ >> 12
|
||||
strh r2, [r1, #6*16]
|
||||
sub r2, r12, r9 @ block[4] = (a3 - b3)
|
||||
mov r2, r2, asr #12 @ >> 12
|
||||
strh r2, [r1, #4*16]
|
||||
add r2, r12, r9 @ block[3] = (a3 + b3)
|
||||
mov r2, r2, asr #12 @ >> 12
|
||||
strh r2, [r1, #3*16]
|
||||
add r2, r3, r8 @ block[2] = (a2 + b2)
|
||||
mov r2, r2, asr #12 @ >> 12
|
||||
strh r2, [r1, #1*16]
|
||||
add r2, r11, r7 @ block[1] = (a1 + b1)
|
||||
mov r2, r2, asr #12 @ >> 12
|
||||
strh r2, [r1, #2*16]
|
||||
add r2, r10, r6 @ block[0] = (a0 + b0)
|
||||
mov r2, r2, asr #12 @ >> 12
|
||||
strh r2, [r1], #2 @ advance to next temp column
|
||||
|
||||
bne .row_loop
|
||||
b .col_start
|
||||
|
||||
@placed here because of ldrd's offset limit
|
||||
L_W1357:
|
||||
.short 2841
|
||||
.short 2408
|
||||
.short 1609
|
||||
.short 565
|
||||
|
||||
L_W0246:
|
||||
.short 2048
|
||||
.short 2676
|
||||
.short 2048
|
||||
.short 1108
|
||||
|
||||
.col_start:
|
||||
@ r0 now points to the temp buffer, where we need it.
|
||||
sub r1, r1, #128+16 @ point r1 back to the input block
|
||||
mov r14, #8 @ loop counter
|
||||
|
||||
.col_loop:
|
||||
ldmia r0!, {r2, r3, r10, r11} @ fetch f0, f2, f4, f6, f1, f3, f5, f7
|
||||
ldrd r4, L_W1357 @ load W1, W3, W5, W7
|
||||
|
||||
smuad r6, r4, r10 @ b0 = W1 * f1 + W3 * f3
|
||||
smultt r7, r5, r10 @ -b1 = W7 * f3
|
||||
smulbt r8, r4, r10 @ -b2 = W1 * f3
|
||||
|
||||
smusdx r9, r10, r5 @ b3 = f1 * W7 - f3 * W5
|
||||
smlabb r7, r4, r11, r7 @ -b1 += W1 * f5
|
||||
rsb r8, r8, #0 @ b2 = -b2
|
||||
smlabb r8, r5, r10, r8 @ b2 += W5 * f1
|
||||
|
||||
smlad r6, r5, r11, r6 @ b0 += W5 * f5 + W7 * f7
|
||||
smlabt r7, r5, r11, r7 @ -b1 += W5 * f7
|
||||
smlatb r8, r5, r11, r8 @ b2 += W7 * f5
|
||||
|
||||
smlsdx r9, r11, r4, r9 @ b3 += f5 * W3 - f7 * W1
|
||||
rsb r7, r7, #0 @ b1 = -b1
|
||||
smlatb r7, r4, r10, r7 @ b1 += W3 * f1
|
||||
smlatt r8, r4, r11, r8 @ b2 += W3 * f7
|
||||
|
||||
ldrd r4, L_W0246 @ load W0, W2, W4, W6
|
||||
add r2, r2, #32 @ DC offset: 0.5
|
||||
|
||||
smulbb r10, r5, r3 @ a0' = W4 * f4
|
||||
smultt r12, r5, r3 @ a3' = W6 * f6
|
||||
smultt r3, r4, r3 @ -a2' = W2 * f6
|
||||
|
||||
rsb r11, r10, #0 @ a1' = -W4 * f4
|
||||
smlabb r10, r4, r2, r10 @ a0' += W0 * f0
|
||||
smlabb r11, r4, r2, r11 @ a1' += W0 * f0
|
||||
smlatt r12, r4, r2, r12 @ a3' += W2 * f2
|
||||
rsb r3, r3, #0 @ a2' = -a2'
|
||||
smlatt r3, r5, r2, r3 @ a2' += W6 * f2
|
||||
|
||||
add r10, r10, r12 @ a0 = a0' + a3'
|
||||
sub r12, r10, r12, lsl #1 @ a3 = a0 - 2 * a3'
|
||||
add r11, r11, r3 @ a1 = a1' + a2'
|
||||
sub r3, r11, r3, lsl #1 @ a2 = a1 - 2 * a2'
|
||||
|
||||
subs r14, r14, #1 @ decrease loop count
|
||||
|
||||
sub r2, r10, r6 @ block[7] = (a0 - b0)
|
||||
mov r2, r2, asr #17 @ >> 17
|
||||
strh r2, [r1, #7*16]
|
||||
sub r2, r11, r7 @ block[6] = (a1 - b1)
|
||||
mov r2, r2, asr #17 @ >> 17
|
||||
strh r2, [r1, #6*16]
|
||||
sub r2, r3, r8 @ block[5] = (a2 - b2)
|
||||
mov r2, r2, asr #17 @ >> 17
|
||||
strh r2, [r1, #5*16]
|
||||
sub r2, r12, r9 @ block[4] = (a3 - b3)
|
||||
mov r2, r2, asr #17 @ >> 17
|
||||
strh r2, [r1, #4*16]
|
||||
add r2, r12, r9 @ block[3] = (a3 + b3)
|
||||
mov r2, r2, asr #17 @ >> 17
|
||||
strh r2, [r1, #3*16]
|
||||
add r2, r3, r8 @ block[2] = (a2 + b2)
|
||||
mov r2, r2, asr #17 @ >> 17
|
||||
strh r2, [r1, #2*16]
|
||||
add r2, r11, r7 @ block[1] = (a1 + b1)
|
||||
mov r2, r2, asr #17 @ >> 17
|
||||
strh r2, [r1, #1*16]
|
||||
add r2, r10, r6 @ block[0] = (a0 + b0)
|
||||
mov r2, r2, asr #17 @ >> 17
|
||||
strh r2, [r1], #2 @ advance to next column
|
||||
|
||||
bne .col_loop
|
||||
|
||||
sub r0, r0, #256 @ point r0 back to the input block
|
||||
ldr pc, [sp], #4
|
||||
|
||||
|
||||
mpeg2_idct_copy:
|
||||
stmfd sp!, {r1-r2, r4-r11, lr}
|
||||
bl .idct
|
||||
ldmfd sp!, {r1-r2}
|
||||
|
||||
add r3, r0, #128
|
||||
mov r8, #0
|
||||
mov r9, #0
|
||||
mov r10, #0
|
||||
mov r11, #0
|
||||
1: @ idct data is in order 0-2-1-3-4-6-5-7,
|
||||
ldmia r0, {r4-r7} @ see above
|
||||
stmia r0!, {r8-r11}
|
||||
usat16 r4, #8, r4
|
||||
usat16 r5, #8, r5
|
||||
orr r4, r4, r5, lsl #8
|
||||
usat16 r6, #8, r6
|
||||
usat16 r7, #8, r7
|
||||
orr r5, r6, r7, lsl #8
|
||||
strd r4, [r1] @ r4, r5
|
||||
add r1, r1, r2
|
||||
cmp r0, r3
|
||||
blo 1b
|
||||
|
||||
ldmfd sp!, {r4-r11, pc}
|
||||
|
||||
mpeg2_idct_add:
|
||||
cmp r0, #129
|
||||
mov r0, r1
|
||||
ldreqsh r1, [r0, #0]
|
||||
bne 1f
|
||||
and r1, r1, #0x70
|
||||
cmp r1, #0x40
|
||||
bne 3f
|
||||
1:
|
||||
stmfd sp!, {r2-r11, lr}
|
||||
bl .idct
|
||||
ldmfd sp!, {r1-r2}
|
||||
|
||||
add r3, r0, #128
|
||||
mov r10, #0
|
||||
mov r11, #0
|
||||
mov r12, #0
|
||||
mov lr, #0
|
||||
ldrd r8, [r1] @ r8, r9
|
||||
2: @ idct data is in order 0-2-1-3-4-6-5-7,
|
||||
ldmia r0, {r4-r7} @ see above
|
||||
stmia r0!, {r10-r12, lr}
|
||||
uxtab16 r4, r4, r8
|
||||
uxtab16 r5, r5, r8, ror #8
|
||||
usat16 r4, #8, r4
|
||||
usat16 r5, #8, r5
|
||||
orr r4, r4, r5, lsl #8
|
||||
uxtab16 r6, r6, r9
|
||||
uxtab16 r7, r7, r9, ror #8
|
||||
usat16 r6, #8, r6
|
||||
usat16 r7, #8, r7
|
||||
orr r5, r6, r7, lsl #8
|
||||
strd r4, [r1] @ r4, r5
|
||||
add r1, r1, r2
|
||||
cmp r0, r3
|
||||
ldrlod r8, [r1] @ r8, r9
|
||||
blo 2b
|
||||
|
||||
ldmfd sp!, {r4-r11, pc}
|
||||
|
||||
3:
|
||||
stmfd sp!, {r4, lr}
|
||||
ldrsh r4, [r0, #0] @ r4 = block[0]
|
||||
mov r12, #0
|
||||
strh r12, [r0, #0] @ block[0] = 0
|
||||
strh r12, [r0, #126] @ block[63] = 0
|
||||
add r4, r4, #64
|
||||
mov r4, r4, asr #7 @ r4 = DC
|
||||
mov r4, r4, lsl #16 @ spread to 2 halfwords
|
||||
orr r4, r4, r4, lsr #16
|
||||
ldrd r0, [r2] @ r0, r1
|
||||
add r12, r2, r3, asl #3
|
||||
4:
|
||||
uxtab16 lr, r4, r0, ror #8
|
||||
uxtab16 r0, r4, r0
|
||||
usat16 lr, #8, lr
|
||||
usat16 r0, #8, r0
|
||||
orr r0, r0, lr, lsl #8
|
||||
uxtab16 lr, r4, r1, ror #8
|
||||
uxtab16 r1, r4, r1
|
||||
usat16 lr, #8, lr
|
||||
usat16 r1, #8, r1
|
||||
orr r1, r1, lr, lsl #8
|
||||
strd r0, [r2] @ r0, r1
|
||||
add r2, r2, r3
|
||||
cmp r2, r12
|
||||
ldrlod r0, [r2] @ r0, r1
|
||||
blo 4b
|
||||
|
||||
ldmfd sp!, {r4, pc}
|
|
@ -1,575 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 Jens Arnold
|
||||
* Based on the work of Karim Boucher and Rani Hod
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
.global mpeg2_idct_copy
|
||||
.type mpeg2_idct_copy, @function
|
||||
.global mpeg2_idct_add
|
||||
.type mpeg2_idct_add, @function
|
||||
|
||||
/* The IDCT itself.
|
||||
* Input: %a0: block pointer
|
||||
* Caller must save all registers. */
|
||||
.align 2
|
||||
.idct:
|
||||
move.l %a0, %a6
|
||||
|
||||
move.l #0, %macsr | signed integer mode
|
||||
|
||||
move.l #((2048<<16)+2841), %a0 | W0, W1
|
||||
move.l #((2676<<16)+2408), %a1 | W2, W3
|
||||
move.l #((2048<<16)+1609), %a2 | W4, W5
|
||||
move.l #((1108<<16)+ 565), %a3 | W6, W7
|
||||
|
||||
lea.l (128,%a6), %a4 | secondary, transposed temp buffer
|
||||
moveq.l #8, %d3 | loop counter
|
||||
|
||||
.row_loop:
|
||||
movem.l (%a6), %d0-%d2/%a5 | fetch (f0, f2, f4, f6, f1, f3, f5, f7)
|
||||
|
||||
mac.w %a0l, %d2u, %acc0 | %acc0 = W1 * f1
|
||||
mac.w %a1l, %d2l, %acc0 | + W3 * f3
|
||||
mac.w %a2l, %a5u, %acc0 | + W5 * f5
|
||||
mac.w %a3l, %a5l, %acc0 | + W7 * f7
|
||||
|
||||
mac.w %a1l, %d2u, %acc1 | %acc1 = W3 * f1
|
||||
msac.w %a3l, %d2l, %acc1 | - W7 * f3
|
||||
msac.w %a0l, %a5u, %acc1 | - W1 * f5
|
||||
msac.w %a2l, %a5l, %acc1 | - W5 * f7
|
||||
|
||||
mac.w %a2l, %d2u, %acc2 | %acc2 = W5 * f1
|
||||
msac.w %a0l, %d2l, %acc2 | - W1 * f3
|
||||
mac.w %a3l, %a5u, %acc2 | + W7 * f5
|
||||
mac.w %a1l, %a5l, %acc2 | + W3 * f7
|
||||
|
||||
mac.w %a3l, %d2u, %acc3 | %acc3 = W7 * f1
|
||||
msac.w %a2l, %d2l, %acc3 | - W5 * f3
|
||||
mac.w %a1l, %a5u, %acc3 | + W3 * f5
|
||||
msac.w %a0l, %a5l, %acc3 | - W1 * f7
|
||||
|
||||
lea.l (16,%a6), %a6 | Advance to next row; put here to fill EMAC latency
|
||||
add.l #(1<<16), %d0 | f0 += 1;
|
||||
|
||||
movclr.l %acc0, %d4 | b0
|
||||
movclr.l %acc1, %d5 | b1
|
||||
movclr.l %acc2, %d6 | b2
|
||||
movclr.l %acc3, %d7 | b3
|
||||
|
||||
mac.w %a0u, %d0u, %acc0 | %acc0 = W0 * f0
|
||||
mac.w %a2u, %d1u, %acc0 | + W4 * f4
|
||||
move.l %acc0, %acc3
|
||||
mac.w %a1u, %d0l, %acc0 | + W2 * f2
|
||||
mac.w %a3u, %d1l, %acc0 | + W6 * f6
|
||||
|
||||
mac.w %a0u, %d0u, %acc1 | %acc1 = W0 * f0
|
||||
msac.w %a2u, %d1u, %acc1 | - W4 * f4
|
||||
move.l %acc1, %acc2
|
||||
mac.w %a3u, %d0l, %acc1 | + W6 * f2
|
||||
msac.w %a1u, %d1l, %acc1 | - W2 * f6
|
||||
|
||||
| ^ move.l %acc1, %acc2 %acc2 = W0 * f0 - W4 * f4
|
||||
msac.w %a3u, %d0l, %acc2 | - W6 * f2
|
||||
mac.w %a1u, %d1l, %acc2 | + W2 * f6
|
||||
|
||||
| ^ move.l %acc0, %acc3 %acc3 = W0 * f0 + W4 * f4
|
||||
msac.w %a1u, %d0l, %acc3 | - W2 * f2
|
||||
msac.w %a3u, %d1l, %acc3 | - W6 * f6
|
||||
|
||||
moveq.l #12, %d1 | shift amount
|
||||
|
||||
move.l %acc0, %d0 | block[7] = (a0
|
||||
sub.l %d4,%d0 | - b0)
|
||||
asr.l %d1, %d0 | >> 12
|
||||
move.w %d0, (7*16,%a4)
|
||||
|
||||
move.l %acc1, %d0 | block[6] = (a1
|
||||
sub.l %d5,%d0 | - b1)
|
||||
asr.l %d1, %d0 | >> 12
|
||||
move.w %d0, (6*16,%a4)
|
||||
|
||||
move.l %acc2, %d0 | block[5] = (a2
|
||||
sub.l %d6,%d0 | - b2)
|
||||
asr.l %d1, %d0 | >> 12
|
||||
move.w %d0, (5*16,%a4)
|
||||
|
||||
move.l %acc3, %d0 | block[4] = (a3
|
||||
sub.l %d7,%d0 | - b3)
|
||||
asr.l %d1, %d0 | >> 12
|
||||
move.w %d0, (4*16,%a4)
|
||||
|
||||
movclr.l %acc3, %d0 | block[3] = (a3
|
||||
add.l %d7, %d0 | + b3)
|
||||
asr.l %d1, %d0 | >> 12
|
||||
move.w %d0, (3*16,%a4)
|
||||
|
||||
movclr.l %acc2, %d0 | block[2] = (a2
|
||||
add.l %d6, %d0 | + b2)
|
||||
asr.l %d1, %d0 | >> 12
|
||||
move.w %d0, (2*16,%a4)
|
||||
|
||||
movclr.l %acc1, %d0 | block[1] = (a1
|
||||
add.l %d5, %d0 | + b1)
|
||||
asr.l %d1, %d0 | >> 12
|
||||
move.w %d0, (1*16,%a4)
|
||||
|
||||
movclr.l %acc0, %d0 | block[0] = (a0
|
||||
add.l %d4, %d0 | + b0)
|
||||
asr.l %d1, %d0 | >> 12
|
||||
move.w %d0, (%a4)+ | advance to next temp column
|
||||
|
||||
subq.l #1, %d3 | loop 8 times
|
||||
bne.w .row_loop
|
||||
|
||||
| %a6 now points to the temp buffer, where we need it.
|
||||
lea.l (-16-128,%a4), %a4 | point %a4 back to the input block
|
||||
moveq.l #8, %d3 | loop counter
|
||||
|
||||
.col_loop:
|
||||
movem.l (%a6), %d0-%d2/%a5 | fetch (f0, f2, f4, f6, f1, f3, f5, f7)
|
||||
|
||||
mac.w %a0l, %d2u, %acc0 | %acc0 = W1 * f1
|
||||
mac.w %a1l, %d2l, %acc0 | + W3 * f3
|
||||
mac.w %a2l, %a5u, %acc0 | + W5 * f5
|
||||
mac.w %a3l, %a5l, %acc0 | + W7 * f7
|
||||
|
||||
mac.w %a1l, %d2u, %acc1 | %acc1 = W3 * f1
|
||||
msac.w %a3l, %d2l, %acc1 | - W7 * f3
|
||||
msac.w %a0l, %a5u, %acc1 | - W1 * f5
|
||||
msac.w %a2l, %a5l, %acc1 | - W5 * f7
|
||||
|
||||
mac.w %a2l, %d2u, %acc2 | %acc2 = W5 * f1
|
||||
msac.w %a0l, %d2l, %acc2 | - W1 * f3
|
||||
mac.w %a3l, %a5u, %acc2 | + W7 * f5
|
||||
mac.w %a1l, %a5l, %acc2 | + W3 * f7
|
||||
|
||||
mac.w %a3l, %d2u, %acc3 | %acc3 = W7 * f1
|
||||
msac.w %a2l, %d2l, %acc3 | - W5 * f3
|
||||
mac.w %a1l, %a5u, %acc3 | + W3 * f5
|
||||
msac.w %a0l, %a5l, %acc3 | - W1 * f7
|
||||
|
||||
lea.l (16,%a6), %a6 | Advance to next row; put here to fill EMAC latency
|
||||
add.l #(32<<16), %d0 | DC offset: 0.5
|
||||
|
||||
movclr.l %acc0, %d4 | b0
|
||||
movclr.l %acc1, %d5 | b1
|
||||
movclr.l %acc2, %d6 | b2
|
||||
movclr.l %acc3, %d7 | b3
|
||||
|
||||
mac.w %a0u, %d0u, %acc0 | %acc0 = W0 * f0
|
||||
mac.w %a2u, %d1u, %acc0 | + W4 * f4
|
||||
move.l %acc0, %acc3
|
||||
mac.w %a1u, %d0l, %acc0 | + W2 * f2
|
||||
mac.w %a3u, %d1l, %acc0 | + W6 * f6
|
||||
|
||||
mac.w %a0u, %d0u, %acc1 | %acc1 = W0 * f0
|
||||
msac.w %a2u, %d1u, %acc1 | - W4 * f4
|
||||
move.l %acc1, %acc2
|
||||
mac.w %a3u, %d0l, %acc1 | + W6 * f2
|
||||
msac.w %a1u, %d1l, %acc1 | - W2 * f6
|
||||
|
||||
| ^ move.l %acc1, %acc2 %acc2 = W0 * f0 - W4 * f4
|
||||
msac.w %a3u, %d0l, %acc2 | - W6 * f2
|
||||
mac.w %a1u, %d1l, %acc2 | + W2 * f6
|
||||
|
||||
| ^ move.l %acc0, %acc3 %acc3 = W0 * f0 + W4 * f4
|
||||
msac.w %a1u, %d0l, %acc3 | - W2 * f2
|
||||
msac.w %a3u, %d1l, %acc3 | - W6 * f6
|
||||
|
||||
moveq.l #17, %d1 | shift amount
|
||||
|
||||
move.l %acc0, %d0 | block[7] = (a0
|
||||
sub.l %d4,%d0 | - b0)
|
||||
asr.l %d1, %d0 | >> 17
|
||||
move.w %d0, (7*16,%a4)
|
||||
|
||||
move.l %acc1, %d0 | block[6] = (a1
|
||||
sub.l %d5,%d0 | - b1)
|
||||
asr.l %d1, %d0 | >> 17
|
||||
move.w %d0, (6*16,%a4)
|
||||
|
||||
move.l %acc2, %d0 | block[5] = (a2
|
||||
sub.l %d6,%d0 | - b2)
|
||||
asr.l %d1, %d0 | >> 17
|
||||
move.w %d0, (5*16,%a4)
|
||||
|
||||
move.l %acc3, %d0 | block[4] = (a3
|
||||
sub.l %d7,%d0 | - b3)
|
||||
asr.l %d1, %d0 | >> 17
|
||||
move.w %d0, (4*16,%a4)
|
||||
|
||||
movclr.l %acc3, %d0 | block[3] = (a3
|
||||
add.l %d7, %d0 | + b3)
|
||||
asr.l %d1, %d0 | >> 17
|
||||
move.w %d0, (3*16,%a4)
|
||||
|
||||
movclr.l %acc2, %d0 | block[2] = (a2
|
||||
add.l %d6, %d0 | + b2)
|
||||
asr.l %d1, %d0 | >> 17
|
||||
move.w %d0, (2*16,%a4)
|
||||
|
||||
movclr.l %acc1, %d0 | block[1] = (a1
|
||||
add.l %d5, %d0 | + b1)
|
||||
asr.l %d1, %d0 | >> 17
|
||||
move.w %d0, (1*16,%a4)
|
||||
|
||||
movclr.l %acc0, %d0 | block[0] = (a0
|
||||
add.l %d4, %d0 | + b0)
|
||||
asr.l %d1, %d0 | >> 17
|
||||
move.w %d0, (%a4)+ | advance to next column
|
||||
|
||||
subq.l #1, %d3 | loop 8 times
|
||||
bne.w .col_loop
|
||||
|
||||
rts
|
||||
|
||||
.align 2
|
||||
|
||||
mpeg2_idct_copy:
|
||||
lea.l (-11*4,%sp), %sp
|
||||
movem.l %d2-%d7/%a2-%a6, (%sp) | save some registers
|
||||
move.l (11*4+4,%sp), %a0 | %a0 - block pointer for idct
|
||||
|
||||
bsr.w .idct | apply idct to block
|
||||
movem.l (11*4+4,%sp), %a0-%a2 | %a0 - block pointer
|
||||
| %a1 - destination pointer
|
||||
| %a2 - stride
|
||||
|
||||
move.l #255, %d1 | preload constant for clipping
|
||||
moveq.l #8, %d4 | loop counter
|
||||
|
||||
.copy_clip_loop:
|
||||
move.w (%a0), %d0 | load block[0]
|
||||
ext.l %d0 | sign extend
|
||||
cmp.l %d1, %d0 | overflow?
|
||||
bls.b 1f
|
||||
spl.b %d0 | yes: set appropriate limit value in low byte
|
||||
1:
|
||||
move.b %d0, %d2 | collect output bytes 0..3 in %d2
|
||||
lsl.l #8, %d2
|
||||
|
||||
move.w (2,%a0), %d0 | load block[1]
|
||||
ext.l %d0 | sign extend
|
||||
cmp.l %d1, %d0 | overflow?
|
||||
bls.b 1f
|
||||
spl.b %d0 | yes: set appropriate limit value in low byte
|
||||
1:
|
||||
move.b %d0, %d2 | collect output bytes 0..3 in %d2
|
||||
lsl.l #8, %d2
|
||||
clr.l (%a0)+ | clear block[0] and block[1],
|
||||
| %a0 now pointing to block[2]
|
||||
move.w (%a0), %d0 | do b2 and b3
|
||||
ext.l %d0
|
||||
cmp.l %d1, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.b %d0, %d2
|
||||
lsl.l #8, %d2
|
||||
|
||||
move.w (2,%a0), %d0
|
||||
ext.l %d0
|
||||
cmp.l %d1, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.b %d0, %d2
|
||||
clr.l (%a0)+
|
||||
|
||||
move.w (%a0), %d0 | do b4 and b5
|
||||
ext.l %d0
|
||||
cmp.l %d1, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.b %d0, %d3
|
||||
lsl.l #8, %d3
|
||||
|
||||
move.w (2,%a0), %d0
|
||||
ext.l %d0
|
||||
cmp.l %d1, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.b %d0, %d3
|
||||
lsl.l #8, %d3
|
||||
clr.l (%a0)+
|
||||
|
||||
move.w (%a0), %d0 | do b6 and b7
|
||||
ext.l %d0
|
||||
cmp.l %d1, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.b %d0, %d3
|
||||
lsl.l #8, %d3
|
||||
|
||||
move.w (2,%a0), %d0
|
||||
ext.l %d0
|
||||
cmp.l %d1, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.b %d0, %d3
|
||||
clr.l (%a0)+
|
||||
|
||||
movem.l %d2-%d3, (%a1) | write all 8 output bytes at once
|
||||
add.l %a2, %a1 | advance output pointer
|
||||
subq.l #1, %d4 | loop 8 times
|
||||
bne.w .copy_clip_loop
|
||||
|
||||
movem.l (%sp), %d2-%d7/%a2-%a6
|
||||
lea.l (11*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.align 2
|
||||
|
||||
mpeg2_idct_add:
|
||||
lea.l (-11*4,%sp), %sp
|
||||
movem.l %d2-%d7/%a2-%a6, (%sp)
|
||||
movem.l (11*4+4,%sp), %d0/%a0-%a2 | %d0 - last value
|
||||
| %a0 - block pointer
|
||||
| %a1 - destination pointer
|
||||
| %a2 - stride
|
||||
|
||||
cmp.l #129, %d0 | last == 129 ?
|
||||
bne.b .idct_add | no: perform idct + addition
|
||||
move.w (%a0), %d0
|
||||
ext.l %d0 | ((block[0]
|
||||
asr.l #4, %d0 | >> 4)
|
||||
and.l #7, %d0 | & 7)
|
||||
subq.l #4, %d0 | - 4 == 0 ?
|
||||
bne.w .dc_add | no: just perform addition
|
||||
|
||||
.idct_add:
|
||||
bsr.w .idct | apply idct
|
||||
movem.l (11*4+8,%sp), %a0-%a2 | reload arguments %a0..%a2
|
||||
|
||||
move.l #255, %d2 | preload constant for clipping
|
||||
clr.l %d3 | used for splitting input words into bytes
|
||||
moveq.l #8, %d4 | loop counter
|
||||
|
||||
.add_clip_loop:
|
||||
movem.l (%a1), %d6-%d7 | fetch (b0 b1 b2 b3) (b4 b5 b6 b7)
|
||||
swap %d6 | (b2 b3 b0 b1)
|
||||
swap %d7 | (b6 b7 b4 b5)
|
||||
|
||||
move.w (2,%a0), %d0 | load block[1]
|
||||
ext.l %d0 | sign extend
|
||||
move.b %d6, %d3 | copy b1
|
||||
lsr.l #8, %d6 | prepare 1st buffer for next byte
|
||||
add.l %d3, %d0 | add b1
|
||||
cmp.l %d2, %d0 | overflow ?
|
||||
bls.b 1f
|
||||
spl.b %d0 | yes: set appropriate limit value in low byte
|
||||
1:
|
||||
move.w (%a0), %d1 | load block[0]
|
||||
ext.l %d1 | sign extend
|
||||
move.b %d6, %d3 | copy b0
|
||||
lsr.l #8, %d6 | prepare 1st buffer for next byte
|
||||
add.l %d3, %d1 | add b0
|
||||
cmp.l %d2, %d1 | overflow ?
|
||||
bls.b 1f
|
||||
spl.b %d1 | yes: set appropriate limit value in low byte
|
||||
1:
|
||||
move.b %d1, %d5 | collect output bytes 0..3 in %d5
|
||||
lsl.l #8, %d5
|
||||
move.b %d0, %d5
|
||||
lsl.l #8, %d5
|
||||
clr.l (%a0)+ | clear block[0] and block[1]
|
||||
| %a0 now pointing to block[2]
|
||||
move.w (2,%a0), %d0 | do b3 and b2
|
||||
ext.l %d0
|
||||
move.b %d6, %d3
|
||||
lsr.l #8, %d6
|
||||
add.l %d3, %d0
|
||||
cmp.l %d2, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.w (%a0), %d1
|
||||
ext.l %d1
|
||||
add.l %d6, %d1
|
||||
cmp.l %d2, %d1
|
||||
bls.b 1f
|
||||
spl.b %d1
|
||||
1:
|
||||
move.b %d1, %d5
|
||||
lsl.l #8, %d5
|
||||
move.b %d0, %d5
|
||||
clr.l (%a0)+
|
||||
|
||||
move.w (2,%a0), %d0 | do b5 and b4
|
||||
ext.l %d0
|
||||
move.b %d7, %d3
|
||||
lsr.l #8, %d7
|
||||
add.l %d3, %d0
|
||||
cmp.l %d2, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.w (%a0), %d1
|
||||
ext.l %d1
|
||||
move.b %d7, %d3
|
||||
lsr.l #8, %d7
|
||||
add.l %d3, %d1
|
||||
cmp.l %d2, %d1
|
||||
bls.b 1f
|
||||
spl.b %d1
|
||||
1:
|
||||
move.b %d1, %d6
|
||||
lsl.l #8, %d6
|
||||
move.b %d0, %d6
|
||||
lsl.l #8, %d6
|
||||
clr.l (%a0)+
|
||||
|
||||
move.w (2,%a0), %d0 | do b7 and b6
|
||||
ext.l %d0
|
||||
move.b %d7, %d3
|
||||
lsr.l #8, %d7
|
||||
add.l %d3, %d0
|
||||
cmp.l %d2, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.w (%a0), %d1
|
||||
ext.l %d1
|
||||
add.l %d7, %d1
|
||||
cmp.l %d2, %d1
|
||||
bls.b 1f
|
||||
spl.b %d1
|
||||
1:
|
||||
move.b %d1, %d6
|
||||
lsl.l #8, %d6
|
||||
move.b %d0, %d6
|
||||
clr.l (%a0)+
|
||||
|
||||
movem.l %d5-%d6, (%a1) | write all 8 output bytes at once
|
||||
add.l %a2, %a1 | advance output pointer
|
||||
subq.l #1, %d4 | loop 8 times
|
||||
bne.w .add_clip_loop
|
||||
|
||||
bra.w .idct_add_end
|
||||
|
||||
.dc_add:
|
||||
move.w (%a0), %d0
|
||||
ext.l %d0 | %d0 = (block[0]
|
||||
add.l #64, %d0 | + 64)
|
||||
asr.l #7, %d0 | >> 7
|
||||
clr.w (%a0) | clear block[0]
|
||||
clr.w (63*2,%a0) | and block[63]
|
||||
move.l %d0, %a0 | DC value in %a0
|
||||
|
||||
move.l #255, %d2 | preload constant for clipping
|
||||
clr.l %d3 | for splitting input words into bytes
|
||||
moveq.l #8, %d4 | loop counter
|
||||
|
||||
.dc_clip_loop:
|
||||
movem.l (%a1), %d6-%d7 | (b0 b1 b2 b3) (b4 b5 b6 b7)
|
||||
swap %d6 | (b2 b3 b0 b1)
|
||||
swap %d7 | (b6 b7 b4 b5)
|
||||
|
||||
move.l %a0, %d0 | copy DC
|
||||
move.b %d6, %d3 | copy b1
|
||||
lsr.l #8, %d6 | prepare 1st buffer for next byte
|
||||
add.l %d3, %d0 | add b1
|
||||
cmp.l %d2, %d0 | overflow ?
|
||||
bls.b 1f
|
||||
spl.b %d0 | yes: set appropriate limit value in low byte
|
||||
1:
|
||||
move.l %a0, %d1 | copy DC
|
||||
move.b %d6, %d3 | copy b0
|
||||
lsr.l #8, %d6 | prepare 1st buffer for next byte
|
||||
add.l %d3, %d1 | add b0
|
||||
cmp.l %d2, %d1 | overflow ?
|
||||
bls.b 1f
|
||||
spl.b %d1 | yes: set appropriate limit value in low byte
|
||||
1:
|
||||
move.b %d1, %d5 | collect output bytes 0..3 in %d5
|
||||
lsl.l #8, %d5
|
||||
move.b %d0, %d5
|
||||
lsl.l #8, %d5
|
||||
|
||||
move.l %a0, %d0 | do b3 and b2
|
||||
move.b %d6, %d3
|
||||
lsr.l #8, %d6
|
||||
add.l %d3, %d0
|
||||
cmp.l %d2, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.l %a0, %d1
|
||||
add.l %d6, %d1
|
||||
cmp.l %d2, %d1
|
||||
bls.b 1f
|
||||
spl.b %d1
|
||||
1:
|
||||
move.b %d1, %d5
|
||||
lsl.l #8, %d5
|
||||
move.b %d0, %d5
|
||||
|
||||
move.l %a0, %d0 | do b5 and b4
|
||||
move.b %d7, %d3
|
||||
lsr.l #8, %d7
|
||||
add.l %d3, %d0
|
||||
cmp.l %d2, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.l %a0, %d1
|
||||
move.b %d7, %d3
|
||||
lsr.l #8, %d7
|
||||
add.l %d3, %d1
|
||||
cmp.l %d2, %d1
|
||||
bls.b 1f
|
||||
spl.b %d1
|
||||
1:
|
||||
move.b %d1, %d6 | do b7 and b6
|
||||
lsl.l #8, %d6
|
||||
move.b %d0, %d6
|
||||
lsl.l #8, %d6
|
||||
|
||||
move.l %a0, %d0
|
||||
move.b %d7, %d3
|
||||
lsr.l #8, %d7
|
||||
add.l %d3, %d0
|
||||
cmp.l %d2, %d0
|
||||
bls.b 1f
|
||||
spl.b %d0
|
||||
1:
|
||||
move.l %a0, %d1
|
||||
add.l %d7, %d1
|
||||
cmp.l %d2, %d1
|
||||
bls.b 1f
|
||||
spl.b %d1
|
||||
1:
|
||||
move.b %d1, %d6
|
||||
lsl.l #8, %d6
|
||||
move.b %d0, %d6
|
||||
|
||||
movem.l %d5-%d6, (%a1) | write all 8 output bytes at once
|
||||
add.l %a2, %a1 | advance output pointer
|
||||
subq.l #1, %d4 | loop 8 times
|
||||
bne.w .dc_clip_loop
|
||||
|
||||
.idct_add_end:
|
||||
movem.l (%sp), %d2-%d7/%a2-%a6
|
||||
lea.l (11*4,%sp), %sp
|
||||
rts
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* $Id$
|
||||
* libmpeg2 sync history:
|
||||
* 2008-07-01 - CVS revision 1.17 - lost compatibility previously to
|
||||
* provide simplified and CPU-optimized motion compensation.
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
#include "mpeg2dec_config.h"
|
||||
|
||||
#include "mpeg2.h"
|
||||
#include "attributes.h"
|
||||
#include "mpeg2_internal.h"
|
||||
|
||||
/* These are defined in their respective target files - motion_comp_X.c */
|
||||
extern mpeg2_mc_fct MC_put_o_16;
|
||||
extern mpeg2_mc_fct MC_put_o_8;
|
||||
extern mpeg2_mc_fct MC_put_x_16;
|
||||
extern mpeg2_mc_fct MC_put_x_8;
|
||||
extern mpeg2_mc_fct MC_put_y_16;
|
||||
extern mpeg2_mc_fct MC_put_y_8;
|
||||
extern mpeg2_mc_fct MC_put_xy_16;
|
||||
extern mpeg2_mc_fct MC_put_xy_8;
|
||||
|
||||
extern mpeg2_mc_fct MC_avg_o_16;
|
||||
extern mpeg2_mc_fct MC_avg_o_8;
|
||||
extern mpeg2_mc_fct MC_avg_x_16;
|
||||
extern mpeg2_mc_fct MC_avg_x_8;
|
||||
extern mpeg2_mc_fct MC_avg_y_16;
|
||||
extern mpeg2_mc_fct MC_avg_y_8;
|
||||
extern mpeg2_mc_fct MC_avg_xy_16;
|
||||
extern mpeg2_mc_fct MC_avg_xy_8;
|
||||
|
||||
const mpeg2_mc_t mpeg2_mc =
|
||||
{
|
||||
{
|
||||
MC_put_o_16, MC_put_x_16, MC_put_y_16, MC_put_xy_16,
|
||||
MC_put_o_8, MC_put_x_8, MC_put_y_8, MC_put_xy_8
|
||||
},
|
||||
{
|
||||
MC_avg_o_16, MC_avg_x_16, MC_avg_y_16, MC_avg_xy_16,
|
||||
MC_avg_o_8, MC_avg_x_8, MC_avg_y_8, MC_avg_xy_8
|
||||
}
|
||||
};
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* motion_comp.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
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
|
||||
#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) \
|
||||
MC_FUNC_16(op, xy) \
|
||||
MC_FUNC_8(op, xy)
|
||||
|
||||
#define MC_FUNC_16(op, xy) \
|
||||
void MC_##op##_##xy##_16 (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); \
|
||||
}
|
||||
|
||||
#define MC_FUNC_8(op, xy) \
|
||||
void MC_##op##_##xy##_8 (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); \
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* motion_comp_arm.c
|
||||
* Copyright (C) 2004 AGAWA Koji <i (AT) atty (DOT) jp>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include "mpeg2.h"
|
||||
#include "attributes.h"
|
||||
#include "mpeg2_internal.h"
|
||||
#include "motion_comp.h"
|
||||
|
||||
/* definitions of the actual mc functions */
|
||||
|
||||
/* MC_FUNC (put, o) <= ASM */
|
||||
MC_FUNC (avg, o)
|
||||
/* MC_FUNC (put, x) <= ASM */
|
||||
MC_FUNC (avg, x)
|
||||
MC_FUNC (put, y)
|
||||
MC_FUNC (avg, y)
|
||||
MC_FUNC (put, xy)
|
||||
MC_FUNC (avg, xy)
|
|
@ -1,342 +0,0 @@
|
|||
@ motion_comp_arm_s.S
|
||||
@ Copyright (C) 2004 AGAWA Koji <i (AT) atty (DOT) jp>
|
||||
@
|
||||
@ 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
|
||||
@
|
||||
@ $Id$
|
||||
|
||||
#include "config.h" /* Rockbox: ARM architecture version */
|
||||
|
||||
.text
|
||||
|
||||
@ ----------------------------------------------------------------
|
||||
.align
|
||||
.global MC_put_o_16
|
||||
MC_put_o_16:
|
||||
@@ void func(uint8_t * dest, const uint8_t * ref, int stride, int height)
|
||||
@@ pld [r1]
|
||||
stmfd sp!, {r4-r7, lr} @ R14 is also called LR
|
||||
and r4, r1, #3
|
||||
ldr pc, [pc, r4, lsl #2]
|
||||
.word 0
|
||||
.word MC_put_o_16_align0
|
||||
.word MC_put_o_16_align1
|
||||
.word MC_put_o_16_align2
|
||||
.word MC_put_o_16_align3
|
||||
|
||||
MC_put_o_16_align0:
|
||||
ldmia r1, {r4-r7}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
stmia r0, {r4-r7}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne MC_put_o_16_align0
|
||||
ldmpc regs=r4-r7 @@ update PC with LR content.
|
||||
|
||||
.macro ADJ_ALIGN_QW shift, R0, R1, R2, R3, R4
|
||||
mov \R0, \R0, lsr #(\shift)
|
||||
orr \R0, \R0, \R1, lsl #(32 - \shift)
|
||||
mov \R1, \R1, lsr #(\shift)
|
||||
orr \R1, \R1, \R2, lsl #(32 - \shift)
|
||||
mov \R2, \R2, lsr #(\shift)
|
||||
orr \R2, \R2, \R3, lsl #(32 - \shift)
|
||||
mov \R3, \R3, lsr #(\shift)
|
||||
orr \R3, \R3, \R4, lsl #(32 - \shift)
|
||||
mov \R4, \R4, lsr #(\shift)
|
||||
.endm
|
||||
|
||||
MC_put_o_16_align1:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r4-r7, r12}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_QW 8, r4, r5, r6, r7, r12
|
||||
stmia r0, {r4-r7}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r4-r7 @@ update PC with LR content.
|
||||
|
||||
MC_put_o_16_align2:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r4-r7, r12}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_QW 16, r4, r5, r6, r7, r12
|
||||
stmia r0, {r4-r7}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r4-r7 @@ update PC with LR content.
|
||||
|
||||
MC_put_o_16_align3:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r4-r7, r12}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_QW 24, r4, r5, r6, r7, r12
|
||||
stmia r0, {r4-r7}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r4-r7 @@ update PC with LR content.
|
||||
|
||||
@ ----------------------------------------------------------------
|
||||
.align
|
||||
.global MC_put_o_8
|
||||
MC_put_o_8:
|
||||
@@ void func(uint8_t * dest, const uint8_t * ref, int stride, int height)
|
||||
@@ pld [r1]
|
||||
stmfd sp!, {r4, r5, lr} @ R14 is also called LR
|
||||
and r4, r1, #3
|
||||
ldr pc, [pc, r4, lsl #2]
|
||||
.word 0
|
||||
.word MC_put_o_8_align0
|
||||
.word MC_put_o_8_align1
|
||||
.word MC_put_o_8_align2
|
||||
.word MC_put_o_8_align3
|
||||
|
||||
MC_put_o_8_align0:
|
||||
ldmia r1, {r4, r5}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
stmia r0, {r4, r5}
|
||||
add r0, r0, r2
|
||||
subs r3, r3, #1
|
||||
bne MC_put_o_8_align0
|
||||
ldmpc regs=r4-r5 @@ update PC with LR content.
|
||||
|
||||
.macro ADJ_ALIGN_DW shift, R0, R1, R2
|
||||
mov \R0, \R0, lsr #(\shift)
|
||||
orr \R0, \R0, \R1, lsl #(32 - \shift)
|
||||
mov \R1, \R1, lsr #(\shift)
|
||||
orr \R1, \R1, \R2, lsl #(32 - \shift)
|
||||
mov \R2, \R2, lsr #(\shift)
|
||||
.endm
|
||||
|
||||
MC_put_o_8_align1:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r4, r5, r12}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_DW 8, r4, r5, r12
|
||||
stmia r0, {r4, r5}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r4-r5 @@ update PC with LR content.
|
||||
|
||||
MC_put_o_8_align2:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r4, r5, r12}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_DW 16, r4, r5, r12
|
||||
stmia r0, {r4, r5}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r4-r5 @@ update PC with LR content.
|
||||
|
||||
MC_put_o_8_align3:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r4, r5, r12}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_DW 24, r4, r5, r12
|
||||
stmia r0, {r4, r5}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r4-r5 @@ update PC with LR content.
|
||||
|
||||
@ ----------------------------------------------------------------
|
||||
.macro AVG_PW rW1, rW2
|
||||
mov \rW2, \rW2, lsl #24
|
||||
orr \rW2, \rW2, \rW1, lsr #8
|
||||
eor r9, \rW1, \rW2
|
||||
#if ARM_ARCH >= 6
|
||||
uhadd8 \rW2, \rW1, \rW2
|
||||
#else
|
||||
and \rW2, \rW1, \rW2
|
||||
and r10, r9, r11
|
||||
add \rW2, \rW2, r10, lsr #1
|
||||
#endif
|
||||
and r9, r9, r12
|
||||
add \rW2, \rW2, r9
|
||||
.endm
|
||||
|
||||
#if ARM_ARCH >= 6
|
||||
#define HIGHEST_REG r9
|
||||
#else
|
||||
#define HIGHEST_REG r11
|
||||
#endif
|
||||
|
||||
.align
|
||||
.global MC_put_x_16
|
||||
MC_put_x_16:
|
||||
@@ void func(uint8_t * dest, const uint8_t * ref, int stride, int height)
|
||||
@@ pld [r1]
|
||||
stmfd sp!, {r4-HIGHEST_REG, lr} @ R14 is also called LR
|
||||
and r4, r1, #3
|
||||
ldr r12, 2f
|
||||
#if ARM_ARCH < 6
|
||||
mvn r11, r12
|
||||
#endif
|
||||
ldr pc, [pc, r4, lsl #2]
|
||||
2: .word 0x01010101
|
||||
.word MC_put_x_16_align0
|
||||
.word MC_put_x_16_align1
|
||||
.word MC_put_x_16_align2
|
||||
.word MC_put_x_16_align3
|
||||
|
||||
MC_put_x_16_align0:
|
||||
ldmia r1, {r4-r8}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
AVG_PW r7, r8
|
||||
AVG_PW r6, r7
|
||||
AVG_PW r5, r6
|
||||
AVG_PW r4, r5
|
||||
stmia r0, {r5-r8}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne MC_put_x_16_align0
|
||||
ldmpc regs=r4-HIGHEST_REG @@ update PC with LR content.
|
||||
|
||||
MC_put_x_16_align1:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r4-r8}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_QW 8, r4, r5, r6, r7, r8
|
||||
AVG_PW r7, r8
|
||||
AVG_PW r6, r7
|
||||
AVG_PW r5, r6
|
||||
AVG_PW r4, r5
|
||||
stmia r0, {r5-r8}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r4-HIGHEST_REG @@ update PC with LR content.
|
||||
|
||||
MC_put_x_16_align2:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r4-r8}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_QW 16, r4, r5, r6, r7, r8
|
||||
AVG_PW r7, r8
|
||||
AVG_PW r6, r7
|
||||
AVG_PW r5, r6
|
||||
AVG_PW r4, r5
|
||||
stmia r0, {r5-r8}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r4-HIGHEST_REG @@ update PC with LR content.
|
||||
|
||||
MC_put_x_16_align3:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r4-r8}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_QW 24, r4, r5, r6, r7, r8
|
||||
AVG_PW r7, r8
|
||||
AVG_PW r6, r7
|
||||
AVG_PW r5, r6
|
||||
AVG_PW r4, r5
|
||||
stmia r0, {r5-r8}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r4-HIGHEST_REG @@ update PC with LR content.
|
||||
|
||||
@ ----------------------------------------------------------------
|
||||
.align
|
||||
.global MC_put_x_8
|
||||
MC_put_x_8:
|
||||
@@ void func(uint8_t * dest, const uint8_t * ref, int stride, int height)
|
||||
@@ pld [r1]
|
||||
stmfd sp!, {r6-HIGHEST_REG, lr} @ R14 is also called LR
|
||||
and r6, r1, #3
|
||||
ldr r12, 2f
|
||||
#if ARM_ARCH < 6
|
||||
mvn r11, r12
|
||||
#endif
|
||||
ldr pc, [pc, r6, lsl #2]
|
||||
2: .word 0x01010101
|
||||
.word MC_put_x_8_align0
|
||||
.word MC_put_x_8_align1
|
||||
.word MC_put_x_8_align2
|
||||
.word MC_put_x_8_align3
|
||||
|
||||
MC_put_x_8_align0:
|
||||
ldmia r1, {r6-r8}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
AVG_PW r7, r8
|
||||
AVG_PW r6, r7
|
||||
stmia r0, {r7-r8}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne MC_put_x_8_align0
|
||||
ldmpc regs=r6-HIGHEST_REG @@ update PC with LR content.
|
||||
|
||||
MC_put_x_8_align1:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r6-r8}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_DW 8, r6, r7, r8
|
||||
AVG_PW r7, r8
|
||||
AVG_PW r6, r7
|
||||
stmia r0, {r7-r8}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r6-HIGHEST_REG @@ update PC with LR content.
|
||||
|
||||
MC_put_x_8_align2:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r6-r8}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_DW 16, r6, r7, r8
|
||||
AVG_PW r7, r8
|
||||
AVG_PW r6, r7
|
||||
stmia r0, {r7-r8}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r6-HIGHEST_REG @@ update PC with LR content.
|
||||
|
||||
MC_put_x_8_align3:
|
||||
and r1, r1, #0xFFFFFFFC
|
||||
1: ldmia r1, {r6-r8}
|
||||
add r1, r1, r2
|
||||
@@ pld [r1]
|
||||
ADJ_ALIGN_DW 24, r6, r7, r8
|
||||
AVG_PW r7, r8
|
||||
AVG_PW r6, r7
|
||||
stmia r0, {r7-r8}
|
||||
subs r3, r3, #1
|
||||
add r0, r0, r2
|
||||
bne 1b
|
||||
ldmpc regs=r6-HIGHEST_REG @@ update PC with LR content.
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include "mpeg2.h"
|
||||
#include "attributes.h"
|
||||
#include "mpeg2_internal.h"
|
||||
#include "motion_comp.h"
|
||||
|
||||
/* 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)
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Based on:
|
||||
* motion_comp_arm.c
|
||||
* Copyright (C) 2004 AGAWA Koji <i (AT) atty (DOT) jp>
|
||||
*
|
||||
* 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"
|
||||
#include "motion_comp.h"
|
||||
|
||||
/* definitions of the actual mc functions */
|
||||
|
||||
/* MC_FUNC (put, o) <= ASM */
|
||||
MC_FUNC (avg, o)
|
||||
/* MC_FUNC (put, x) <= ASM */
|
||||
MC_FUNC (avg, x)
|
||||
MC_FUNC (put, y)
|
||||
MC_FUNC (avg, y)
|
||||
MC_FUNC (put, xy)
|
||||
MC_FUNC (avg, xy)
|
|
@ -1,436 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 Jens Arnold
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
.macro LEFT8_PW dW1, dW2 | needs %d0 == 24, clobbers %d2
|
||||
lsl.l #8, \dW1 | changes dW1, keeps dW2
|
||||
move.l \dW2, %d2
|
||||
lsr.l %d0, %d2
|
||||
or.l %d2, \dW1
|
||||
.endm
|
||||
|
||||
.macro LEFT24_PW dW1, dW2 | needs %d0 == 24, clobbers %d2
|
||||
lsl.l %d0, \dW1 | changes dW1, keeps dW2
|
||||
move.l \dW2, %d2
|
||||
lsr.l #8, %d2
|
||||
or.l %d2, \dW1
|
||||
.endm
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
.align 2
|
||||
.global MC_put_o_8
|
||||
.type MC_put_o_8, @function
|
||||
|
||||
MC_put_o_8:
|
||||
movem.l (4,%sp), %a0-%a1 | dest, source
|
||||
move.l %a1, %d0
|
||||
and.l #3, %d0
|
||||
sub.l %d0, %a1 | align source
|
||||
jmp.l (2, %pc, %d0.l*4)
|
||||
bra.w .po8_0
|
||||
bra.w .po8_1
|
||||
bra.w .po8_2
|
||||
| last table entry coincides with target
|
||||
|
||||
.po8_3:
|
||||
lea.l (-5*4,%sp), %sp
|
||||
movem.l %d2-%d5/%a2, (%sp) | save some registers
|
||||
move.l (5*4+12,%sp), %a2 | stride
|
||||
move.l (5*4+16,%sp), %d1 | height
|
||||
moveq.l #24, %d0 | shift amount
|
||||
1:
|
||||
movem.l (%a1), %d3-%d5
|
||||
add.l %a2, %a1
|
||||
LEFT24_PW %d3, %d4
|
||||
lsl.l %d0, %d4
|
||||
lsr.l #8, %d5
|
||||
or.l %d5, %d4
|
||||
movem.l %d3-%d4, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d1
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d5/%a2
|
||||
lea.l (5*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.po8_2:
|
||||
lea.l (-3*4,%sp), %sp
|
||||
movem.l %d2-%d4, (%sp) | save some registers
|
||||
movem.l (3*4+12,%sp), %d0-%d1 | stride, height
|
||||
1:
|
||||
movem.l (%a1), %d2-%d4
|
||||
add.l %d0, %a1
|
||||
swap %d2
|
||||
swap %d3
|
||||
move.w %d3, %d2
|
||||
swap %d4
|
||||
move.w %d4, %d3
|
||||
movem.l %d2-%d3, (%a0)
|
||||
add.l %d0, %a0
|
||||
subq.l #1, %d1
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d4
|
||||
lea.l (3*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.po8_1:
|
||||
lea.l (-5*4,%sp), %sp
|
||||
movem.l %d2-%d5/%a2, (%sp) | save some registers
|
||||
move.l (5*4+12,%sp), %a2 | stride
|
||||
move.l (5*4+16,%sp), %d1 | height
|
||||
moveq.l #24, %d0 | shift amount
|
||||
1:
|
||||
movem.l (%a1), %d3-%d5
|
||||
add.l %a2, %a1
|
||||
LEFT8_PW %d3, %d4
|
||||
lsl.l #8, %d4
|
||||
lsr.l %d0, %d5
|
||||
or.l %d5, %d4
|
||||
movem.l %d3-%d4, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d1
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d5/%a2
|
||||
lea.l (5*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.po8_0:
|
||||
movem.l (12,%sp), %d0-%d1 | stride, height
|
||||
subq.l #4, %d0 | adjust for increment within the loop
|
||||
1:
|
||||
move.l (%a1)+, (%a0)+
|
||||
move.l (%a1), (%a0)
|
||||
add.l %d0, %a0
|
||||
add.l %d0, %a1
|
||||
subq.l #1, %d1
|
||||
bne.s 1b
|
||||
rts
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
.align 2
|
||||
.global MC_put_o_16
|
||||
.type MC_put_o_16, @function
|
||||
|
||||
MC_put_o_16:
|
||||
lea.l (-7*4,%sp), %sp
|
||||
movem.l %d2-%d7/%a2, (%sp) | save some registers
|
||||
movem.l (7*4+4,%sp), %a0-%a2| dest, source, stride
|
||||
move.l (7*4+16,%sp), %d1 | height
|
||||
move.l %a1, %d0
|
||||
and.l #3, %d0
|
||||
sub.l %d0, %a1
|
||||
jmp.l (2, %pc, %d0.l*4)
|
||||
bra.w .po16_0
|
||||
bra.w .po16_1
|
||||
bra.w .po16_2
|
||||
| last table entry coincides with target
|
||||
|
||||
.po16_3:
|
||||
moveq.l #24, %d0 | shift amount
|
||||
1:
|
||||
movem.l (%a1), %d3-%d7
|
||||
add.l %a2, %a1
|
||||
LEFT24_PW %d3, %d4
|
||||
LEFT24_PW %d4, %d5
|
||||
LEFT24_PW %d5, %d6
|
||||
lsl.l %d0, %d6
|
||||
lsr.l #8, %d7
|
||||
or.l %d7, %d6
|
||||
movem.l %d3-%d6, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d1
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d7/%a2
|
||||
lea.l (7*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.po16_2:
|
||||
1:
|
||||
movem.l (%a1), %d3-%d7
|
||||
add.l %a2, %a1
|
||||
swap %d3
|
||||
swap %d4
|
||||
move.w %d4, %d3
|
||||
swap %d5
|
||||
move.w %d5, %d4
|
||||
swap %d6
|
||||
move.w %d6, %d5
|
||||
swap %d7
|
||||
move.w %d7, %d6
|
||||
movem.l %d3-%d6, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d1
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d7/%a2
|
||||
lea.l (7*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.po16_1:
|
||||
moveq.l #24, %d0 | shift amount
|
||||
1:
|
||||
movem.l (%a1), %d3-%d7
|
||||
add.l %a2, %a1
|
||||
LEFT8_PW %d3, %d4
|
||||
LEFT8_PW %d4, %d5
|
||||
LEFT8_PW %d5, %d6
|
||||
lsl.l #8, %d6
|
||||
lsr.l %d0, %d7
|
||||
or.l %d7, %d6
|
||||
movem.l %d3-%d6, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d1
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d7/%a2
|
||||
lea.l (7*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.po16_0:
|
||||
1:
|
||||
movem.l (%a1), %d3-%d6
|
||||
add.l %a2, %a1
|
||||
movem.l %d3-%d6, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d1
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d7/%a2
|
||||
lea.l (7*4,%sp), %sp
|
||||
rts
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
.macro AVG_PW dW1, dW2 | needs %d0 == 24, clobbers %d1, %d2,
|
||||
move.l \dW1, %d1 | changes dW1, keeps dW2
|
||||
lsl.l #8, \dW1
|
||||
move.l \dW2, %d2
|
||||
lsr.l %d0, %d2
|
||||
or.l %d2, \dW1
|
||||
move.l %d1, %d2
|
||||
eor.l \dW1, %d1
|
||||
and.l %d2, \dW1
|
||||
move.l #0xfefefefe, %d2
|
||||
and.l %d1, %d2
|
||||
eor.l %d2, %d1
|
||||
lsr.l #1, %d2
|
||||
add.l %d2, \dW1
|
||||
add.l %d1, \dW1
|
||||
.endm
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
.align 2
|
||||
.global MC_put_x_8
|
||||
.type MC_put_x_8, @function
|
||||
|
||||
MC_put_x_8:
|
||||
lea.l (-6*4,%sp), %sp
|
||||
movem.l %d2-%d6/%a2, (%sp) | save some registers
|
||||
movem.l (6*4+4,%sp), %a0-%a2| dest, source, stride
|
||||
move.l (6*4+16,%sp), %d6 | height
|
||||
move.l %a1, %d0
|
||||
and.l #3, %d0
|
||||
sub.l %d0, %a1
|
||||
jmp.l (2, %pc, %d0.l*4)
|
||||
bra.w .px8_0
|
||||
bra.w .px8_1
|
||||
bra.w .px8_2
|
||||
| last table entry coincides with target
|
||||
|
||||
.px8_3:
|
||||
moveq.l #24, %d0
|
||||
1:
|
||||
movem.l (%a1), %d3-%d5
|
||||
add.l %a2, %a1
|
||||
LEFT24_PW %d3, %d4
|
||||
LEFT24_PW %d4, %d5
|
||||
lsl.l %d0, %d5
|
||||
AVG_PW %d3, %d4
|
||||
AVG_PW %d4, %d5
|
||||
movem.l %d3-%d4, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d6
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d6/%a2
|
||||
lea.l (6*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.px8_2:
|
||||
moveq.l #24, %d0
|
||||
1:
|
||||
movem.l (%a1), %d3-%d5
|
||||
add.l %a2, %a1
|
||||
swap %d3
|
||||
swap %d4
|
||||
move.w %d4, %d3
|
||||
swap %d5
|
||||
move.w %d5, %d4
|
||||
AVG_PW %d3, %d4
|
||||
AVG_PW %d4, %d5
|
||||
movem.l %d3-%d4, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d6
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d6/%a2
|
||||
lea.l (6*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.px8_1:
|
||||
moveq.l #24, %d0
|
||||
1:
|
||||
movem.l (%a1), %d3-%d5
|
||||
add.l %a2, %a1
|
||||
LEFT8_PW %d3, %d4
|
||||
LEFT8_PW %d4, %d5
|
||||
lsl.l #8, %d5
|
||||
AVG_PW %d3, %d4
|
||||
AVG_PW %d4, %d5
|
||||
movem.l %d3-%d4, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d6
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d6/%a2
|
||||
lea.l (6*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.px8_0:
|
||||
moveq.l #24, %d0
|
||||
1:
|
||||
movem.l (%a1), %d3-%d5
|
||||
add.l %a2, %a1
|
||||
AVG_PW %d3, %d4
|
||||
AVG_PW %d4, %d5
|
||||
movem.l %d3-%d4, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %d6
|
||||
bne.s 1b
|
||||
movem.l (%sp), %d2-%d6/%a2
|
||||
lea.l (6*4,%sp), %sp
|
||||
rts
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
.align 2
|
||||
.global MC_put_x_16
|
||||
.type MC_put_x_16, @function
|
||||
|
||||
MC_put_x_16:
|
||||
lea.l (-8*4,%sp), %sp
|
||||
movem.l %d2-%d7/%a2-%a3, (%sp) | save some registers
|
||||
movem.l (8*4+4,%sp), %a0-%a3 | dest, source, stride, height
|
||||
move.l %a1, %d0
|
||||
and.l #3, %d0
|
||||
sub.l %d0, %a1
|
||||
jmp.l (2, %pc, %d0.l*4)
|
||||
bra.w .px16_0
|
||||
bra.w .px16_1
|
||||
bra.w .px16_2
|
||||
| last table entry coincides with target
|
||||
|
||||
.px16_3:
|
||||
moveq.l #24, %d0
|
||||
1:
|
||||
movem.l (%a1), %d3-%d7
|
||||
add.l %a2, %a1
|
||||
LEFT24_PW %d3, %d4
|
||||
LEFT24_PW %d4, %d5
|
||||
LEFT24_PW %d5, %d6
|
||||
LEFT24_PW %d6, %d7
|
||||
lsl.l %d0, %d7
|
||||
AVG_PW %d3, %d4
|
||||
AVG_PW %d4, %d5
|
||||
AVG_PW %d5, %d6
|
||||
AVG_PW %d6, %d7
|
||||
movem.l %d3-%d6, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %a3
|
||||
tst.l %a3
|
||||
bne.w 1b
|
||||
movem.l (%sp), %d2-%d7/%a2-%a3
|
||||
lea.l (8*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.px16_2:
|
||||
moveq.l #24, %d0
|
||||
1:
|
||||
movem.l (%a1), %d3-%d7
|
||||
add.l %a2, %a1
|
||||
swap %d3
|
||||
swap %d4
|
||||
move.w %d4, %d3
|
||||
swap %d5
|
||||
move.w %d5, %d4
|
||||
swap %d6
|
||||
move.w %d6, %d5
|
||||
swap %d7
|
||||
move.w %d7, %d6
|
||||
AVG_PW %d3, %d4
|
||||
AVG_PW %d4, %d5
|
||||
AVG_PW %d5, %d6
|
||||
AVG_PW %d6, %d7
|
||||
movem.l %d3-%d6, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %a3
|
||||
tst.l %a3
|
||||
bne.w 1b
|
||||
movem.l (%sp), %d2-%d7/%a2-%a3
|
||||
lea.l (8*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.px16_1:
|
||||
moveq.l #24, %d0
|
||||
1:
|
||||
movem.l (%a1), %d3-%d7
|
||||
add.l %a2, %a1
|
||||
LEFT8_PW %d3, %d4
|
||||
LEFT8_PW %d4, %d5
|
||||
LEFT8_PW %d5, %d6
|
||||
LEFT8_PW %d6, %d7
|
||||
lsl.l #8, %d7
|
||||
AVG_PW %d3, %d4
|
||||
AVG_PW %d4, %d5
|
||||
AVG_PW %d5, %d6
|
||||
AVG_PW %d6, %d7
|
||||
movem.l %d3-%d6, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %a3
|
||||
tst.l %a3
|
||||
bne.w 1b
|
||||
movem.l (%sp), %d2-%d7/%a2-%a3
|
||||
lea.l (8*4,%sp), %sp
|
||||
rts
|
||||
|
||||
.px16_0:
|
||||
moveq.l #24, %d0
|
||||
1:
|
||||
movem.l (%a1), %d3-%d7
|
||||
add.l %a2, %a1
|
||||
AVG_PW %d3, %d4
|
||||
AVG_PW %d4, %d5
|
||||
AVG_PW %d5, %d6
|
||||
AVG_PW %d6, %d7
|
||||
movem.l %d3-%d6, (%a0)
|
||||
add.l %a2, %a0
|
||||
subq.l #1, %a3
|
||||
tst.l %a3
|
||||
bne.w 1b
|
||||
movem.l (%sp), %d2-%d7/%a2-%a3
|
||||
lea.l (8*4,%sp), %sp
|
||||
rts
|
|
@ -1,223 +0,0 @@
|
|||
/*
|
||||
* mpeg2.h
|
||||
* Copyright (C) 2000-2004 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
|
||||
*
|
||||
* $Id$
|
||||
* libmpeg2 sync history:
|
||||
* 2008-07-01 - CVS revision 1.67
|
||||
*/
|
||||
|
||||
#ifndef MPEG2_H
|
||||
#define MPEG2_H
|
||||
|
||||
#include "mpeg2dec_config.h"
|
||||
|
||||
#define MPEG2_VERSION(a,b,c) (((a)<<16)|((b)<<8)|(c))
|
||||
#define MPEG2_RELEASE MPEG2_VERSION (0, 5, 0) /* 0.5.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 0x00
|
||||
#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;
|
||||
} 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[MPEG2_COMPONENTS];
|
||||
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_INTERNAL_NORETURN = -1,
|
||||
STATE_BUFFER = 0,
|
||||
STATE_SEQUENCE = 1,
|
||||
STATE_SEQUENCE_REPEATED = 2,
|
||||
STATE_SEQUENCE_MODIFIED = 3,
|
||||
STATE_GOP = 4,
|
||||
STATE_PICTURE = 5,
|
||||
STATE_SLICE_1ST = 6,
|
||||
STATE_PICTURE_2ND = 7,
|
||||
STATE_SLICE = 8,
|
||||
STATE_END = 9,
|
||||
STATE_INVALID = 10,
|
||||
STATE_INVALID_END = 11,
|
||||
} mpeg2_state_t;
|
||||
|
||||
typedef struct mpeg2_convert_init_s
|
||||
{
|
||||
unsigned int id_size;
|
||||
unsigned int buf_size[MPEG2_COMPONENTS];
|
||||
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,
|
||||
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[MPEG2_COMPONENTS],
|
||||
void * id);
|
||||
void mpeg2_custom_fbuf (mpeg2dec_t * mpeg2dec, int custom_fbuf);
|
||||
|
||||
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[MPEG2_COMPONENTS],
|
||||
uint8_t * forward_fbuf[MPEG2_COMPONENTS],
|
||||
uint8_t * backward_fbuf[MPEG2_COMPONENTS]);
|
||||
void mpeg2_slice (mpeg2_decoder_t * decoder, int code, const uint8_t * buffer);
|
||||
|
||||
int mpeg2_guess_aspect (const mpeg2_sequence_t * sequence,
|
||||
unsigned int * pixel_width,
|
||||
unsigned int * pixel_height);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MPEG2_ALLOC_MPEG2DEC = 0,
|
||||
MPEG2_ALLOC_CHUNK = 1,
|
||||
MPEG2_ALLOC_YUV = 2,
|
||||
MPEG2_ALLOC_CONVERT_ID = 3,
|
||||
MPEG2_ALLOC_CONVERTED = 4,
|
||||
MPEG_ALLOC_CODEC_MALLOC,
|
||||
MPEG_ALLOC_CODEC_CALLOC,
|
||||
MPEG_ALLOC_MPEG2_BUFFER,
|
||||
MPEG_ALLOC_AUDIOBUF,
|
||||
MPEG_ALLOC_PCMOUT,
|
||||
MPEG_ALLOC_DISKBUF,
|
||||
__MPEG_ALLOC_FIRST = -256,
|
||||
} mpeg2_alloc_t;
|
||||
|
||||
void * mpeg2_malloc (unsigned size, mpeg2_alloc_t reason);
|
||||
#if 0
|
||||
void mpeg2_free (void * buf);
|
||||
#endif
|
||||
/* allocates a dedicated buffer and locks all previous allocation in place */
|
||||
void * mpeg2_bufalloc(unsigned size, mpeg2_alloc_t reason);
|
||||
/* clears all non-dedicated buffer space */
|
||||
void mpeg2_mem_reset(void);
|
||||
void mpeg2_alloc_init(unsigned char* buf, int mallocsize);
|
||||
|
||||
#endif /* MPEG2_H */
|
|
@ -1,274 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* $Id$
|
||||
* libmpeg2 sync history:
|
||||
* 2008-07-01 - CVS revision 1.89
|
||||
*/
|
||||
#ifndef MPEG2_INTERNAL_H
|
||||
#define MPEG2_INTERNAL_H
|
||||
|
||||
#include "config.h" /* for Rockbox CPU_ #defines */
|
||||
|
||||
/* 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][MPEG2_COMPONENTS];
|
||||
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[MPEG2_COMPONENTS];
|
||||
|
||||
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[MPEG2_COMPONENTS];
|
||||
|
||||
/* DCT coefficients */
|
||||
int16_t * DCTblock; /* put buffer separately to have it in IRAM */
|
||||
|
||||
uint8_t * picture_dest[MPEG2_COMPONENTS];
|
||||
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];
|
||||
|
||||
/* 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;
|
||||
/* 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;
|
||||
};
|
||||
|
||||
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 * ATTR_ALIGN(4) chunk_buffer;
|
||||
/* pointer to start of the current chunk */
|
||||
uint8_t * chunk_start;
|
||||
/* pointer to current position in chunk_buffer */
|
||||
uint8_t * chunk_ptr;
|
||||
/* last start code ? */
|
||||
uint8_t 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][MPEG2_COMPONENTS];
|
||||
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];
|
||||
};
|
||||
|
||||
/* decode.c */
|
||||
mpeg2_state_t mpeg2_seek_header (mpeg2dec_t * mpeg2dec);
|
||||
mpeg2_state_t mpeg2_parse_header (mpeg2dec_t * mpeg2dec);
|
||||
|
||||
/* header.c */
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
/* idct.c */
|
||||
void mpeg2_idct_init (void);
|
||||
void mpeg2_idct_copy(int16_t * block, uint8_t * dest,
|
||||
const int stride);
|
||||
void mpeg2_idct_add(const int last, int16_t * block,
|
||||
uint8_t * dest, const int stride);
|
||||
|
||||
extern const uint8_t default_mpeg2_scan_norm[64];
|
||||
extern const uint8_t default_mpeg2_scan_alt[64];
|
||||
extern uint8_t mpeg2_scan_norm[64];
|
||||
extern uint8_t mpeg2_scan_alt[64];
|
||||
|
||||
/* motion_comp.c */
|
||||
void mpeg2_mc_init (void);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mpeg2_mc_fct * put [8];
|
||||
mpeg2_mc_fct * avg [8];
|
||||
} mpeg2_mc_t;
|
||||
|
||||
extern const mpeg2_mc_t mpeg2_mc;
|
||||
|
||||
#endif /* MPEG2_INTERNAL_H */
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
/* $Id$ */
|
||||
#ifndef MPEG2DEC_CONFIG_H
|
||||
#define MPEG2DEC_CONFIG_H
|
||||
|
||||
#define ATTRIBUTE_ALIGNED_MAX 16
|
||||
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
#define MPEG2_COLOR 1
|
||||
#define MPEG2_COMPONENTS 3
|
||||
#else
|
||||
#define MPEG2_COLOR 0
|
||||
#define MPEG2_COMPONENTS 1
|
||||
#endif
|
||||
|
||||
#endif /* MPEG2DEC_CONFIG_H */
|
File diff suppressed because it is too large
Load diff
|
@ -1,433 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* $Id$
|
||||
* libmpeg2 sync history:
|
||||
* 2008-07-01 - CVS revision 1.12
|
||||
*/
|
||||
|
||||
#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 [] ICONST_ATTR = {
|
||||
{INTRA|QUANT, 2}, {INTRA, 1}
|
||||
};
|
||||
|
||||
#define MC MACROBLOCK_MOTION_FORWARD
|
||||
#define CODED MACROBLOCK_PATTERN
|
||||
|
||||
static const MBtab MB_P [] ICONST_ATTR = {
|
||||
{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 [] ICONST_ATTR = {
|
||||
{0, 6}, {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 [] ICONST_ATTR = {
|
||||
{ 3, 6}, { 2, 4}, { 1, 3}, { 1, 3}, { 0, 2}, { 0, 2}, { 0, 2}, { 0, 2}
|
||||
};
|
||||
|
||||
static const MVtab MV_10 [] ICONST_ATTR = {
|
||||
{ 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 [] ICONST_ATTR = {
|
||||
{ 0, 1}, { 0, 1}, { 1, 2}, {-1, 2}
|
||||
};
|
||||
|
||||
|
||||
static const CBPtab CBP_7 [] ICONST_ATTR = {
|
||||
{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 [] ICONST_ATTR = {
|
||||
{0, 9}, {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 [] ICONST_ATTR = {
|
||||
{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 [] ICONST_ATTR = {
|
||||
{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 [] ICONST_ATTR = {
|
||||
{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 [] ICONST_ATTR = {
|
||||
{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 [] ICONST_ATTR = {
|
||||
{ 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 [] ICONST_ATTR = {
|
||||
{ 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 [] ICONST_ATTR = {
|
||||
{ 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 [] ICONST_ATTR = {
|
||||
{ 65, 0, 12}, { 65, 0, 12}, { 65, 0, 12}, { 65, 0, 12},
|
||||
{ 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 [] ICONST_ATTR = {
|
||||
{ 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 [] ICONST_ATTR = {
|
||||
{ 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 [] ICONST_ATTR = {
|
||||
{ 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 [] ICONST_ATTR = {
|
||||
{ 65, 0, 12}, { 65, 0, 12}, { 65, 0, 12}, { 65, 0, 12},
|
||||
{ 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 [] ICONST_ATTR = {
|
||||
{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 [] ICONST_ATTR = {
|
||||
{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}
|
||||
};
|
|
@ -1,32 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 by Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef MPEG_ALLOC_H
|
||||
#define MPEG_ALLOC_H
|
||||
|
||||
/* returns the remaining mpeg2 buffer and it's size */
|
||||
void * mpeg2_get_buf(size_t *size);
|
||||
void *mpeg_malloc(size_t size, mpeg2_alloc_t reason);
|
||||
/* Grabs all the buffer available sans margin */
|
||||
void *mpeg_malloc_all(size_t *size_out, mpeg2_alloc_t reason);
|
||||
/* Initializes the malloc buffer with the given base buffer */
|
||||
bool mpeg_alloc_init(unsigned char *buf, size_t mallocsize);
|
||||
|
||||
#endif /* MPEG_ALLOC_H */
|
|
@ -1,227 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Miscellaneous helper API definitions
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "plugin.h"
|
||||
#include "mpegplayer.h"
|
||||
|
||||
/** Streams **/
|
||||
|
||||
/* Initializes the cursor */
|
||||
void stream_scan_init(struct stream_scan *sk)
|
||||
{
|
||||
dbuf_l2_init(&sk->l2);
|
||||
}
|
||||
|
||||
/* Ensures direction is -1 or 1 and margin is properly initialized */
|
||||
void stream_scan_normalize(struct stream_scan *sk)
|
||||
{
|
||||
if (sk->dir >= 0)
|
||||
{
|
||||
sk->dir = SSCAN_FORWARD;
|
||||
sk->margin = sk->len;
|
||||
}
|
||||
else if (sk->dir < 0)
|
||||
{
|
||||
sk->dir = SSCAN_REVERSE;
|
||||
sk->margin = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Moves a scan cursor. If amount is positive, the increment is in the scan
|
||||
* direction, otherwise opposite the scan direction */
|
||||
void stream_scan_offset(struct stream_scan *sk, off_t by)
|
||||
{
|
||||
off_t bydir = by*sk->dir;
|
||||
sk->pos += bydir;
|
||||
sk->margin -= bydir;
|
||||
sk->len -= by;
|
||||
}
|
||||
|
||||
/** Time helpers **/
|
||||
void ts_to_hms(uint32_t pts, struct hms *hms)
|
||||
{
|
||||
hms->frac = pts % TS_SECOND;
|
||||
hms->sec = pts / TS_SECOND;
|
||||
hms->min = hms->sec / 60;
|
||||
hms->hrs = hms->min / 60;
|
||||
hms->sec %= 60;
|
||||
hms->min %= 60;
|
||||
}
|
||||
|
||||
void hms_format(char *buf, size_t bufsize, struct hms *hms)
|
||||
{
|
||||
/* Only display hours if nonzero */
|
||||
if (hms->hrs != 0)
|
||||
{
|
||||
rb->snprintf(buf, bufsize, "%u:%02u:%02u",
|
||||
hms->hrs, hms->min, hms->sec);
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->snprintf(buf, bufsize, "%u:%02u",
|
||||
hms->min, hms->sec);
|
||||
}
|
||||
}
|
||||
|
||||
/** Maths **/
|
||||
uint32_t muldiv_uint32(uint32_t multiplicand,
|
||||
uint32_t multiplier,
|
||||
uint32_t divisor)
|
||||
{
|
||||
if (divisor != 0)
|
||||
{
|
||||
uint64_t prod = (uint64_t)multiplier*multiplicand + divisor/2;
|
||||
|
||||
if ((uint32_t)(prod >> 32) < divisor)
|
||||
return (uint32_t)(prod / divisor);
|
||||
}
|
||||
else if (multiplicand == 0 || multiplier == 0)
|
||||
{
|
||||
return 0; /* 0/0 = 0 : yaya */
|
||||
}
|
||||
/* else (> 0) / 0 = UINT32_MAX */
|
||||
|
||||
return UINT32_MAX; /* Saturate */
|
||||
}
|
||||
|
||||
|
||||
/** Lists **/
|
||||
|
||||
/* Does the list have any members? */
|
||||
bool list_is_empty(void **list)
|
||||
{
|
||||
return *list == NULL;
|
||||
}
|
||||
|
||||
/* Is the item inserted into a particular list? */
|
||||
bool list_is_member(void **list, void *item)
|
||||
{
|
||||
return *rb->find_array_ptr(list, item) != NULL;
|
||||
}
|
||||
|
||||
/* Removes an item from a list - returns true if item was found
|
||||
* and thus removed. */
|
||||
bool list_remove_item(void **list, void *item)
|
||||
{
|
||||
return rb->remove_array_ptr(list, item) != -1;
|
||||
}
|
||||
|
||||
/* Adds a list item, insert last, if not already present. */
|
||||
void list_add_item(void **list, void *item)
|
||||
{
|
||||
void **item_p = rb->find_array_ptr(list, item);
|
||||
if (*item_p == NULL)
|
||||
*item_p = item;
|
||||
}
|
||||
|
||||
/* Clears the entire list. */
|
||||
void list_clear_all(void **list)
|
||||
{
|
||||
while (*list != NULL)
|
||||
*list++ = NULL;
|
||||
}
|
||||
|
||||
/* Enumerate all items in the array, passing each item in turn to the
|
||||
* callback as well as the data value. The current item may be safely
|
||||
* removed. Other changes during enumeration are undefined. The callback
|
||||
* may return 'false' to stop the enumeration early. */
|
||||
void list_enum_items(void **list,
|
||||
list_enum_callback_t callback,
|
||||
void* data)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
void *item = *list;
|
||||
|
||||
if (item == NULL)
|
||||
break;
|
||||
|
||||
if (callback != NULL && !callback(item, data))
|
||||
break;
|
||||
|
||||
if (*list == item)
|
||||
list++; /* Item still there */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** System events **/
|
||||
static long mpeg_sysevent_id;
|
||||
|
||||
void mpeg_sysevent_clear(void)
|
||||
{
|
||||
mpeg_sysevent_id = 0;
|
||||
}
|
||||
|
||||
void mpeg_sysevent_set(void)
|
||||
{
|
||||
/* Nonzero and won't invoke anything in default event handler */
|
||||
mpeg_sysevent_id = ACTION_STD_CANCEL;
|
||||
}
|
||||
|
||||
long mpeg_sysevent(void)
|
||||
{
|
||||
return mpeg_sysevent_id;
|
||||
}
|
||||
|
||||
int mpeg_sysevent_callback(int btn,
|
||||
const struct menu_item_ex *menu,
|
||||
struct gui_synclist *this_list)
|
||||
{
|
||||
(void) this_list;
|
||||
switch (btn)
|
||||
{
|
||||
case SYS_USB_CONNECTED:
|
||||
case SYS_POWEROFF:
|
||||
case SYS_REBOOT:
|
||||
mpeg_sysevent_id = btn;
|
||||
return ACTION_STD_CANCEL;
|
||||
}
|
||||
|
||||
return btn;
|
||||
(void)menu;
|
||||
}
|
||||
|
||||
void mpeg_sysevent_handle(void)
|
||||
{
|
||||
long id = mpeg_sysevent();
|
||||
if (id != 0)
|
||||
rb->default_event_handler(id);
|
||||
}
|
||||
|
||||
|
||||
/** Buttons **/
|
||||
|
||||
int mpeg_button_get(int timeout)
|
||||
{
|
||||
int button;
|
||||
|
||||
mpeg_sysevent_clear();
|
||||
button = timeout == TIMEOUT_BLOCK ? rb->button_get(true) :
|
||||
rb->button_get_w_tmo(timeout);
|
||||
|
||||
/* Produce keyclick */
|
||||
rb->keyclick_click(true, button);
|
||||
|
||||
return mpeg_sysevent_callback(button, NULL, NULL);
|
||||
}
|
||||
|
|
@ -1,258 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Miscellaneous helper API declarations
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef MPEG_MISC_H
|
||||
#define MPEG_MISC_H
|
||||
|
||||
/* Miscellaneous helpers */
|
||||
#ifndef ALIGNED_ATTR
|
||||
#define ALIGNED_ATTR(x) __attribute__((aligned(x)))
|
||||
#endif
|
||||
|
||||
#include "disk_buf.h"
|
||||
|
||||
/* Generic states for when things are too simple to care about naming them */
|
||||
enum state_enum
|
||||
{
|
||||
STATE0 = 0,
|
||||
STATE1,
|
||||
STATE2,
|
||||
STATE3,
|
||||
STATE4,
|
||||
STATE5,
|
||||
STATE6,
|
||||
STATE7,
|
||||
STATE8,
|
||||
STATE9,
|
||||
};
|
||||
|
||||
/* Macros for comparing memory bytes to a series of constant bytes in an
|
||||
efficient manner - evaluate to true if corresponding bytes match */
|
||||
#if defined (CPU_ARM)
|
||||
/* ARM must load 32-bit values at addres % 4 == 0 offsets but this data
|
||||
isn't aligned nescessarily, so just byte compare */
|
||||
#define CMP_3_CONST(_a, _b) \
|
||||
({ int _x; \
|
||||
asm volatile ( \
|
||||
"ldrb %[x], [%[a], #0] \n" \
|
||||
"eors %[x], %[x], %[b0] \n" \
|
||||
"ldreqb %[x], [%[a], #1] \n" \
|
||||
"eoreqs %[x], %[x], %[b1] \n" \
|
||||
"ldreqb %[x], [%[a], #2] \n" \
|
||||
"eoreqs %[x], %[x], %[b2] \n" \
|
||||
: [x]"=&r"(_x) \
|
||||
: [a]"r"(_a), \
|
||||
[b0]"i"(((_b) >> 24) & 0xff), \
|
||||
[b1]"i"(((_b) >> 16) & 0xff), \
|
||||
[b2]"i"(((_b) >> 8) & 0xff) \
|
||||
); \
|
||||
_x == 0; })
|
||||
|
||||
#define CMP_4_CONST(_a, _b) \
|
||||
({ int _x; \
|
||||
asm volatile ( \
|
||||
"ldrb %[x], [%[a], #0] \n" \
|
||||
"eors %[x], %[x], %[b0] \n" \
|
||||
"ldreqb %[x], [%[a], #1] \n" \
|
||||
"eoreqs %[x], %[x], %[b1] \n" \
|
||||
"ldreqb %[x], [%[a], #2] \n" \
|
||||
"eoreqs %[x], %[x], %[b2] \n" \
|
||||
"ldreqb %[x], [%[a], #3] \n" \
|
||||
"eoreqs %[x], %[x], %[b3] \n" \
|
||||
: [x]"=&r"(_x) \
|
||||
: [a]"r"(_a), \
|
||||
[b0]"i"(((_b) >> 24) & 0xff), \
|
||||
[b1]"i"(((_b) >> 16) & 0xff), \
|
||||
[b2]"i"(((_b) >> 8) & 0xff), \
|
||||
[b3]"i"(((_b) ) & 0xff) \
|
||||
); \
|
||||
_x == 0; })
|
||||
|
||||
#elif defined (CPU_COLDFIRE)
|
||||
/* Coldfire can just load a 32 bit value at any offset but ASM is not the
|
||||
best way to integrate this with the C code */
|
||||
#define CMP_3_CONST(a, b) \
|
||||
(((*(uint32_t *)(a) >> 8) == ((uint32_t)(b) >> 8)))
|
||||
|
||||
#define CMP_4_CONST(a, b) \
|
||||
((*(uint32_t *)(a) == (b)))
|
||||
|
||||
#else
|
||||
/* Don't know what this is - use bytewise comparisons */
|
||||
#define CMP_3_CONST(a, b) \
|
||||
(( ((a)[0] ^ (((b) >> 24) & 0xff)) | \
|
||||
((a)[1] ^ (((b) >> 16) & 0xff)) | \
|
||||
((a)[2] ^ (((b) >> 8) & 0xff)) ) == 0)
|
||||
|
||||
#define CMP_4_CONST(a, b) \
|
||||
(( ((a)[0] ^ (((b) >> 24) & 0xff)) | \
|
||||
((a)[1] ^ (((b) >> 16) & 0xff)) | \
|
||||
((a)[2] ^ (((b) >> 8) & 0xff)) | \
|
||||
((a)[3] ^ (((b) ) & 0xff)) ) == 0)
|
||||
#endif /* CPU_* */
|
||||
|
||||
|
||||
/** Streams **/
|
||||
|
||||
/* Convert PTS/DTS ticks to our clock ticks */
|
||||
#define TS_TO_TICKS(pts) ((uint64_t)CLOCK_RATE*(pts) / TS_SECOND)
|
||||
/* Convert our clock ticks to PTS/DTS ticks */
|
||||
#define TICKS_TO_TS(ts) ((uint64_t)TS_SECOND*(ts) / CLOCK_RATE)
|
||||
/* Convert timecode ticks to our clock ticks */
|
||||
#define TC_TO_TICKS(stamp) ((uint64_t)CLOCK_RATE*(stamp) / TC_SECOND)
|
||||
/* Convert our clock ticks to timecode ticks */
|
||||
#define TICKS_TO_TC(stamp) ((uint64_t)TC_SECOND*(stamp) / CLOCK_RATE)
|
||||
/* Convert timecode ticks to timestamp ticks */
|
||||
#define TC_TO_TS(stamp) ((stamp) / 600)
|
||||
|
||||
/*
|
||||
* S = start position, E = end position
|
||||
*
|
||||
* pos:
|
||||
* initialize to search start position (S)
|
||||
*
|
||||
* len:
|
||||
* initialize to = ABS(S-E)
|
||||
* scanning = remaining bytes in scan direction
|
||||
*
|
||||
* dir:
|
||||
* scan direction; >= 0 == forward, < 0 == reverse
|
||||
*
|
||||
* margin:
|
||||
* amount of data to right of cursor - initialize by stream_scan_normalize
|
||||
*
|
||||
* data:
|
||||
* Extra data used/returned by the function implemented
|
||||
*
|
||||
* Forward scan:
|
||||
* S pos E
|
||||
* | *<-margin->| dir->
|
||||
* | |<--len--->|
|
||||
*
|
||||
* Reverse scan:
|
||||
* E pos S
|
||||
* |<-len->*<-margin->| <-dir
|
||||
* | | |
|
||||
*/
|
||||
struct stream_scan
|
||||
{
|
||||
off_t pos; /* Initial scan position (file offset) */
|
||||
ssize_t len; /* Maximum length of scan */
|
||||
off_t dir; /* Direction - >= 0; forward, < 0 backward */
|
||||
ssize_t margin; /* Used by function to track margin between position and data end */
|
||||
intptr_t data; /* */
|
||||
struct dbuf_l2_cache l2;
|
||||
};
|
||||
|
||||
#define SSCAN_REVERSE (-1)
|
||||
#define SSCAN_FORWARD 1
|
||||
|
||||
/* Initializes the cursor */
|
||||
void stream_scan_init(struct stream_scan *sk);
|
||||
|
||||
/* Ensures direction is -1 or 1 and margin is properly initialized */
|
||||
void stream_scan_normalize(struct stream_scan *sk);
|
||||
|
||||
/* Moves a scan cursor. If amount is positive, the increment is in the scan
|
||||
* direction, otherwise opposite the scan direction */
|
||||
void stream_scan_offset(struct stream_scan *sk, off_t by);
|
||||
|
||||
/** Time helpers **/
|
||||
struct hms
|
||||
{
|
||||
unsigned int hrs;
|
||||
unsigned int min;
|
||||
unsigned int sec;
|
||||
unsigned int frac;
|
||||
};
|
||||
|
||||
void ts_to_hms(uint32_t ts, struct hms *hms);
|
||||
void hms_format(char *buf, size_t bufsize, struct hms *hms);
|
||||
|
||||
/** Maths **/
|
||||
|
||||
/* Moving average */
|
||||
#define AVERAGE(var, x, count) \
|
||||
({ typeof (count) _c = (count); \
|
||||
((var) * (_c-1) + (x)) / (_c); })
|
||||
|
||||
/* Multiply two unsigned 32-bit integers yielding a 64-bit result and
|
||||
* divide by another unsigned 32-bit integer to yield a 32-bit result.
|
||||
* Rounds to nearest with saturation. */
|
||||
uint32_t muldiv_uint32(uint32_t multiplicand,
|
||||
uint32_t multiplier,
|
||||
uint32_t divisor);
|
||||
|
||||
|
||||
/** Lists **/
|
||||
|
||||
/* Does the list have any members? */
|
||||
bool list_is_empty(void **list);
|
||||
|
||||
/* Is the item inserted into a particular list? */
|
||||
bool list_is_member(void **list, void *item);
|
||||
|
||||
/* Removes an item from a list - returns true if item was found
|
||||
* and thus removed. */
|
||||
bool list_remove_item(void **list, void *item);
|
||||
|
||||
/* Adds a list item, insert last, if not already present. */
|
||||
void list_add_item(void **list, void *item);
|
||||
|
||||
/* Clears the entire list. */
|
||||
void list_clear_all(void **list);
|
||||
|
||||
/* Enumerate all items in the array. */
|
||||
typedef bool (*list_enum_callback_t)(void *item, void* data);
|
||||
|
||||
void list_enum_items(void **list,
|
||||
list_enum_callback_t callback,
|
||||
void *data);
|
||||
|
||||
|
||||
/** System events **/
|
||||
|
||||
/* Clear event */
|
||||
void mpeg_sysevent_clear(void);
|
||||
|
||||
/* Set to ACTION_STD_CANCEL */
|
||||
void mpeg_sysevent_set(void);
|
||||
|
||||
/* Get event code */
|
||||
long mpeg_sysevent(void);
|
||||
|
||||
/* Call with a system event code and used as menu callback */
|
||||
int mpeg_sysevent_callback(int btn, const struct menu_item_ex *menu,
|
||||
struct gui_synclist *this_list);
|
||||
|
||||
/* Handle recorded event */
|
||||
void mpeg_sysevent_handle(void);
|
||||
|
||||
|
||||
/** Buttons **/
|
||||
|
||||
/* Get button codes while remembering important events for later
|
||||
* processing; return of ACTION_STD_CANCEL means plugin should
|
||||
* abort and handle the event */
|
||||
int mpeg_button_get(int timeout);
|
||||
|
||||
#endif /* MPEG_MISC_H */
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,110 +0,0 @@
|
|||
|
||||
#include "plugin.h"
|
||||
|
||||
#define SETTINGS_VERSION 5
|
||||
#define SETTINGS_MIN_VERSION 1
|
||||
#define SETTINGS_FILENAME "mpegplayer.cfg"
|
||||
|
||||
#if defined(TOSHIBA_GIGABEAT_F) || defined(SANSA_E200) || defined(SANSA_C200) \
|
||||
|| defined(IRIVER_H10) || defined(COWON_D2) || defined(PHILIPS_HDD1630) \
|
||||
|| defined(SANSA_FUZE) || defined(SANSA_E200V2) || defined(SANSA_FUZEV2) \
|
||||
|| defined(TOSHIBA_GIGABEAT_S) || defined(PHILIPS_SA9200)
|
||||
#define MPEG_OPTION_DITHERING_ENABLED 1
|
||||
#endif
|
||||
|
||||
#ifndef MPEG_OPTION_DITHERING_ENABLED
|
||||
#define MPEG_OPTION_DITHERING_ENABLED 0
|
||||
#endif
|
||||
|
||||
enum mpeg_option_id
|
||||
{
|
||||
#if MPEG_OPTION_DITHERING_ENABLED
|
||||
MPEG_OPTION_DITHERING,
|
||||
#endif
|
||||
MPEG_OPTION_DISPLAY_FPS,
|
||||
MPEG_OPTION_LIMIT_FPS,
|
||||
MPEG_OPTION_SKIP_FRAMES,
|
||||
#ifdef HAVE_BACKLIGHT_BRIGHTNESS
|
||||
MPEG_OPTION_BACKLIGHT_BRIGHTNESS,
|
||||
#endif
|
||||
};
|
||||
|
||||
enum mpeg_audio_option_id
|
||||
{
|
||||
MPEG_AUDIO_TONE_CONTROLS,
|
||||
MPEG_AUDIO_CHANNEL_MODES,
|
||||
MPEG_AUDIO_CROSSFEED,
|
||||
MPEG_AUDIO_EQUALIZER,
|
||||
MPEG_AUDIO_DITHERING,
|
||||
};
|
||||
|
||||
enum mpeg_resume_id
|
||||
{
|
||||
MPEG_RESUME_MENU_ALWAYS = 0,
|
||||
MPEG_RESUME_MENU_IF_INCOMPLETE,
|
||||
MPEG_RESUME_RESTART,
|
||||
MPEG_RESUME_ALWAYS,
|
||||
MPEG_RESUME_NUM_OPTIONS,
|
||||
};
|
||||
|
||||
enum mpeg_start_id
|
||||
{
|
||||
MPEG_START_RESTART,
|
||||
MPEG_START_RESUME,
|
||||
MPEG_START_SEEK,
|
||||
MPEG_START_SETTINGS,
|
||||
MPEG_START_QUIT,
|
||||
MPEG_START_EXIT,
|
||||
};
|
||||
|
||||
enum mpeg_setting_id
|
||||
{
|
||||
MPEG_SETTING_DISPLAY_SETTINGS,
|
||||
MPEG_SETTING_AUDIO_SETTINGS,
|
||||
MPEG_SETTING_ENABLE_START_MENU,
|
||||
MPEG_SETTING_PLAY_MODE,
|
||||
MPEG_SETTING_CLEAR_RESUMES,
|
||||
};
|
||||
|
||||
enum mpeg_menu_id
|
||||
{
|
||||
MPEG_MENU_SETTINGS,
|
||||
MPEG_MENU_RESUME,
|
||||
MPEG_MENU_QUIT,
|
||||
};
|
||||
|
||||
struct mpeg_settings {
|
||||
int showfps; /* flag to display fps */
|
||||
int limitfps; /* flag to limit fps */
|
||||
int skipframes; /* flag to skip frames */
|
||||
int resume_options; /* type of resume action at start */
|
||||
int resume_count; /* total # of resumes in config file */
|
||||
int resume_time; /* resume time for current mpeg (in half minutes) */
|
||||
char resume_filename[MAX_PATH]; /* filename of current mpeg */
|
||||
#if MPEG_OPTION_DITHERING_ENABLED
|
||||
int displayoptions;
|
||||
#endif
|
||||
int play_mode; /* play single file or all files in directory */
|
||||
/* Audio options - simple on/off specification */
|
||||
int tone_controls;
|
||||
int channel_modes;
|
||||
int crossfeed;
|
||||
int equalizer;
|
||||
int dithering;
|
||||
/* Backlight options */
|
||||
#ifdef HAVE_BACKLIGHT_BRIGHTNESS
|
||||
int backlight_brightness;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern struct mpeg_settings settings;
|
||||
|
||||
int mpeg_start_menu(uint32_t duration);
|
||||
int mpeg_menu(void);
|
||||
|
||||
void init_settings(const char* filename);
|
||||
void save_settings(void);
|
||||
|
||||
#ifdef HAVE_BACKLIGHT_BRIGHTNESS
|
||||
void mpeg_backlight_update_brightness(int value);
|
||||
#endif
|
|
@ -1,122 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Stream definitions for MPEG
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef MPEG_STREAM_H
|
||||
#define MPEG_STREAM_H
|
||||
|
||||
/* Codes for various header byte sequences - MSB represents lowest memory
|
||||
address */
|
||||
#define PACKET_START_CODE_PREFIX 0x00000100ul
|
||||
#define END_CODE 0x000001b9ul
|
||||
#define PACK_START_CODE 0x000001baul
|
||||
#define SYSTEM_HEADER_START_CODE 0x000001bbul
|
||||
|
||||
/* p = base pointer, b0 - b4 = byte offsets from p */
|
||||
/* We only care about the MS 32 bits of the 33 and so the ticks are 45kHz */
|
||||
#define TS_FROM_HEADER(p, b0) \
|
||||
((uint32_t)((((p)[(b0)+0] & 0x0e) << 28) | \
|
||||
(((p)[(b0)+1] ) << 21) | \
|
||||
(((p)[(b0)+2] & 0xfe) << 13) | \
|
||||
(((p)[(b0)+3] ) << 6) | \
|
||||
(((p)[(b0)+4] ) >> 2)))
|
||||
|
||||
#define TS_CHECK_MARKERS(p, b0) \
|
||||
(((((p)[(b0)+0] & 0x01) << 2) | \
|
||||
(((p)[(b0)+2] & 0x01) << 1) | \
|
||||
(((p)[(b0)+4] & 0x01) )) == 0x07)
|
||||
|
||||
/* Get the SCR in our 45kHz ticks. Ignore the 9-bit extension */
|
||||
#define MPEG2_PACK_HEADER_SCR(p, b0) \
|
||||
((uint32_t)((((p)[(b0)+0] & 0x38) << 26) | \
|
||||
(((p)[(b0)+0] & 0x03) << 27) | \
|
||||
(((p)[(b0)+1] ) << 19) | \
|
||||
(((p)[(b0)+2] & 0xf8) << 11) | \
|
||||
(((p)[(b0)+2] & 0x03) << 12) | \
|
||||
(((p)[(b0)+3] ) << 4) | \
|
||||
(((p)[(b0)+4] ) >> 4)))
|
||||
|
||||
#define MPEG2_CHECK_PACK_SCR_MARKERS(ph, b0) \
|
||||
(((((ph)[(b0)+0] & 0x04) ) | \
|
||||
(((ph)[(b0)+2] & 0x04) >> 1) | \
|
||||
(((ph)[(b0)+4] & 0x04) >> 2)) == 0x07)
|
||||
|
||||
#define INVALID_TIMESTAMP (~(uint32_t)0)
|
||||
#define MAX_TIMESTAMP (INVALID_TIMESTAMP-1)
|
||||
#define TS_SECOND (45000) /* Timestamp ticks per second */
|
||||
#define TC_SECOND (27000000) /* MPEG timecode ticks per second */
|
||||
|
||||
/* These values immediately follow the start code prefix '00 00 01' */
|
||||
|
||||
/* Video start codes */
|
||||
#define MPEG_START_PICTURE 0x00
|
||||
#define MPEG_START_SLICE_FIRST 0x01
|
||||
#define MPEG_START_SLICE_LAST 0xaf
|
||||
#define MPEG_START_RESERVED_1 0xb0
|
||||
#define MPEG_START_RESERVED_2 0xb1
|
||||
#define MPEG_START_USER_DATA 0xb2
|
||||
#define MPEG_START_SEQUENCE_HEADER 0xb3
|
||||
#define MPEG_START_SEQUENCE_ERROR 0xb4
|
||||
#define MPEG_START_EXTENSION 0xb5
|
||||
#define MPEG_START_RESERVED_3 0xb6
|
||||
#define MPEG_START_SEQUENCE_END 0xb7
|
||||
#define MPEG_START_GOP 0xb8
|
||||
|
||||
/* Stream IDs */
|
||||
#define MPEG_STREAM_PROGRAM_END 0xb9
|
||||
#define MPEG_STREAM_PACK_HEADER 0xba
|
||||
#define MPEG_STREAM_SYSTEM_HEADER 0xbb
|
||||
#define MPEG_STREAM_PROGRAM_STREAM_MAP 0xbc
|
||||
#define MPEG_STREAM_PRIVATE_1 0xbd
|
||||
#define MPEG_STREAM_PADDING 0xbe
|
||||
#define MPEG_STREAM_PRIVATE_2 0xbf
|
||||
#define MPEG_STREAM_AUDIO_FIRST 0xc0
|
||||
#define MPEG_STREAM_AUDIO_LAST 0xcf
|
||||
#define MPEG_STREAM_VIDEO_FIRST 0xe0
|
||||
#define MPEG_STREAM_VIDEO_LAST 0xef
|
||||
#define MPEG_STREAM_ECM 0xf0
|
||||
#define MPEG_STREAM_EMM 0xf1
|
||||
/* ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A or
|
||||
* ISO/IEC 13818-6_DSMCC_stream */
|
||||
#define MPEG_STREAM_MISC_1 0xf2
|
||||
/* ISO/IEC_13522_stream */
|
||||
#define MPEG_STREAM_MISC_2 0xf3
|
||||
/* ITU-T Rec. H.222.1 type A - E */
|
||||
#define MPEG_STREAM_MISC_3 0xf4
|
||||
#define MPEG_STREAM_MISC_4 0xf5
|
||||
#define MPEG_STREAM_MISC_5 0xf6
|
||||
#define MPEG_STREAM_MISC_6 0xf7
|
||||
#define MPEG_STREAM_MISC_7 0xf8
|
||||
#define MPEG_STREAM_ANCILLARY 0xf9
|
||||
#define MPEG_STREAM_RESERVED_FIRST 0xfa
|
||||
#define MPEG_STREAM_RESERVED_LAST 0xfe
|
||||
/* Program stream directory */
|
||||
#define MPEG_STREAM_PROGRAM_DIRECTORY 0xff
|
||||
|
||||
#define STREAM_IS_AUDIO(s) (((s) & 0xf0) == 0xc0)
|
||||
#define STREAM_IS_VIDEO(s) (((s) & 0xf0) == 0xe0)
|
||||
|
||||
#define MPEG_MAX_PACKET_SIZE (64*1024+16)
|
||||
|
||||
/* Largest MPEG audio frame - MPEG1, Layer II, 384kbps, 32kHz, pad */
|
||||
#define MPA_MAX_FRAME_SIZE 1729
|
||||
|
||||
#endif /* MPEG_STREAM_H */
|
File diff suppressed because it is too large
Load diff
|
@ -1,95 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Main mpegplayer config header.
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef MPEGPLAYER_H
|
||||
#define MPEGPLAYER_H
|
||||
|
||||
#ifdef HAVE_SCHEDULER_BOOSTCTRL
|
||||
#define trigger_cpu_boost rb->trigger_cpu_boost
|
||||
#define cancel_cpu_boost rb->cancel_cpu_boost
|
||||
#endif
|
||||
/* #else function-like empty macros are defined in the headers */
|
||||
|
||||
/* Should be enough for now */
|
||||
#define MPEGPLAYER_MAX_STREAMS 4
|
||||
|
||||
/* Memory allotments for various subsystems */
|
||||
#define MIN_MEMMARGIN (4*1024)
|
||||
|
||||
/** Video thread **/
|
||||
#define LIBMPEG2_ALLOC_SIZE (2*1024*1024)
|
||||
|
||||
/** MPEG audio buffer **/
|
||||
#define AUDIOBUF_GUARD_SIZE (MPA_MAX_FRAME_SIZE + 2*MAD_BUFFER_GUARD)
|
||||
#define AUDIOBUF_SIZE (64*1024)
|
||||
#define AUDIOBUF_ALLOC_SIZE (AUDIOBUF_SIZE+AUDIOBUF_GUARD_SIZE)
|
||||
|
||||
/** PCM buffer **/
|
||||
#define CLOCK_RATE 44100 /* Our clock rate in ticks/second (samplerate) */
|
||||
|
||||
/* Define this as "1" to have a test tone instead of silence clip */
|
||||
#define SILENCE_TEST_TONE 0
|
||||
|
||||
/* NOTE: Sizes make no frame header allowance when considering duration */
|
||||
#define PCMOUT_BUFSIZE (CLOCK_RATE/2*4) /* 1/2s */
|
||||
#define PCMOUT_GUARD_SIZE (PCMOUT_BUFSIZE) /* guarantee contiguous sizes */
|
||||
#define PCMOUT_ALLOC_SIZE (PCMOUT_BUFSIZE + PCMOUT_GUARD_SIZE)
|
||||
/* Start pcm playback @ 25% full */
|
||||
#define PCMOUT_PLAY_WM (PCMOUT_BUFSIZE/4)
|
||||
#define PCMOUT_LOW_WM (0)
|
||||
|
||||
/** disk buffer **/
|
||||
#define DISK_BUF_LOW_WATERMARK (1024*1024)
|
||||
/* 65535+6 is required since each PES has a 6 byte header with a 16 bit
|
||||
* packet length field */
|
||||
#define DISK_GUARDBUF_SIZE ALIGN_UP(65535+6, 4)
|
||||
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
#define mylcd_splash rb->splash
|
||||
#else
|
||||
#include "lib/grey.h"
|
||||
#define mylcd_splash grey_splash
|
||||
#endif
|
||||
|
||||
#include "lib/mylcd.h"
|
||||
|
||||
#include "libmpeg2/mpeg2.h"
|
||||
#include "video_out.h"
|
||||
#include "mpeg_stream.h"
|
||||
#include "mpeg_misc.h"
|
||||
#include "mpeg_alloc.h"
|
||||
#include "stream_thread.h"
|
||||
#include "parser.h"
|
||||
#include "pcm_output.h"
|
||||
#include "disk_buf.h"
|
||||
#include "stream_mgr.h"
|
||||
|
||||
#define LCD_ENABLE_EVENT_0 MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 0)
|
||||
#define LCD_ENABLE_EVENT_1 MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 1)
|
||||
|
||||
#ifdef PLUGIN_USE_IRAM
|
||||
/* IRAM preserving mechanism to enable talking menus */
|
||||
extern void mpegplayer_iram_preserve(void);
|
||||
extern void mpegplayer_iram_restore(void);
|
||||
#endif
|
||||
|
||||
#endif /* MPEGPLAYER_H */
|
|
@ -1,32 +0,0 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
|
||||
MPEGSRCDIR := $(APPSDIR)/plugins/mpegplayer
|
||||
MPEGBUILDDIR := $(BUILDDIR)/apps/plugins/mpegplayer
|
||||
|
||||
ROCKS += $(MPEGBUILDDIR)/mpegplayer.rock
|
||||
|
||||
MPEG_SRC := $(call preprocess, $(MPEGSRCDIR)/SOURCES)
|
||||
MPEG_OBJ := $(call c2obj, $(MPEG_SRC))
|
||||
|
||||
# add source files to OTHER_SRC to get automatic dependencies
|
||||
OTHER_SRC += $(MPEG_SRC)
|
||||
|
||||
# Set '-fgnu89-inline' if supported (GCCVER >= 4.1.3, GCCNUM > 401)
|
||||
ifeq ($(shell expr $(GCCNUM) \> 401),1)
|
||||
MPEGCFLAGS = $(PLUGINFLAGS) -fgnu89-inline
|
||||
else
|
||||
MPEGCFLAGS = $(PLUGINFLAGS)
|
||||
endif
|
||||
|
||||
$(MPEGBUILDDIR)/mpegplayer.rock: $(MPEG_OBJ) $(CODECDIR)/libmad-mpeg.a
|
||||
|
||||
$(MPEGBUILDDIR)/%.o: $(MPEGSRCDIR)/%.c $(MPEGSRCDIR)/mpegplayer.make
|
||||
$(SILENT)mkdir -p $(dir $@)
|
||||
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(MPEGCFLAGS) -c $< -o $@
|
|
@ -1,103 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* AV parser inteface declarations
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
enum stream_formats
|
||||
{
|
||||
STREAM_FMT_UNKNOWN = -1,
|
||||
STREAM_FMT_MPEG_TS, /* MPEG transport stream */
|
||||
STREAM_FMT_MPEG_PS, /* MPEG program stream */
|
||||
STREAM_FMT_MPV, /* MPEG Video only (1 or 2) */
|
||||
STREAM_FMT_MPA, /* MPEG Audio only */
|
||||
};
|
||||
|
||||
/* Structure used by a thread that handles a single demuxed data stream and
|
||||
* receives commands from the stream manager */
|
||||
enum stream_parse_states
|
||||
{
|
||||
/* Stream is... */
|
||||
SSTATE_SYNC, /* synchronizing by trying to find a start code */
|
||||
SSTATE_PARSE, /* parsing the stream looking for packets */
|
||||
SSTATE_END, /* at the end of data */
|
||||
};
|
||||
|
||||
enum stream_parse_mode
|
||||
{
|
||||
STREAM_PM_STREAMING = 0, /* Next packet when streaming */
|
||||
STREAM_PM_RANDOM_ACCESS, /* Random-access parsing */
|
||||
};
|
||||
|
||||
enum stream_parser_flags
|
||||
{
|
||||
STREAMF_CAN_SEEK = 0x1, /* Seeking possible for this stream */
|
||||
};
|
||||
|
||||
struct stream_parser
|
||||
{
|
||||
/* Common generic parser data */
|
||||
enum stream_formats format; /* Stream format */
|
||||
uint32_t start_pts; /* The movie start time as represented by
|
||||
the first audio PTS tag in the
|
||||
stream converted to half minutes */
|
||||
uint32_t end_pts; /* The movie end time as represented by
|
||||
the maximum audio PTS tag in the
|
||||
stream converted to half minutes */
|
||||
uint32_t duration; /* Duration in PTS units */
|
||||
unsigned flags; /* Various attributes set at init */
|
||||
struct vo_ext dims; /* Movie dimensions in pixels */
|
||||
uint32_t last_seek_time;
|
||||
int (*next_data)(struct stream *str, enum stream_parse_mode type);
|
||||
union /* A place for reusable no-cache parameters */
|
||||
{
|
||||
struct str_sync_data sd;
|
||||
} parms;
|
||||
};
|
||||
|
||||
extern struct stream_parser str_parser;
|
||||
|
||||
/* MPEG parsing */
|
||||
uint8_t * mpeg_parser_scan_start_code(struct stream_scan *sk, uint32_t code);
|
||||
unsigned mpeg_parser_scan_pes(struct stream_scan *sk);
|
||||
uint32_t mpeg_parser_scan_scr(struct stream_scan *sk);
|
||||
uint32_t mpeg_parser_scan_pts(struct stream_scan *sk, unsigned id);
|
||||
off_t mpeg_stream_stream_seek_PTS(uint32_t time, int id);
|
||||
|
||||
/* General parsing */
|
||||
bool parser_init(void);
|
||||
void str_initialize(struct stream *str, off_t pos);
|
||||
bool parser_prepare_image(uint32_t time);
|
||||
bool parser_get_video_size(struct vo_ext *sz);
|
||||
int parser_init_stream(void);
|
||||
void parser_close_stream(void);
|
||||
static inline bool parser_can_seek(void)
|
||||
{ return str_parser.flags & STREAMF_CAN_SEEK; }
|
||||
uint32_t parser_seek_time(uint32_t time);
|
||||
void parser_prepare_streaming(void);
|
||||
void str_end_of_stream(struct stream *str);
|
||||
|
||||
static inline int parser_get_next_data(struct stream *str,
|
||||
enum stream_parse_mode type)
|
||||
{ return str_parser.next_data(str, type); }
|
||||
|
||||
#endif /* PARSER_H */
|
|
@ -1,396 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* PCM output buffer definitions
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "plugin.h"
|
||||
#include "mpegplayer.h"
|
||||
|
||||
/* PCM channel we're using */
|
||||
#define MPEG_PCM_CHANNEL PCM_MIXER_CHAN_PLAYBACK
|
||||
|
||||
/* Pointers */
|
||||
|
||||
/* Start of buffer */
|
||||
static struct pcm_frame_header * ALIGNED_ATTR(4) pcm_buffer;
|
||||
/* End of buffer (not guard) */
|
||||
static struct pcm_frame_header * ALIGNED_ATTR(4) pcmbuf_end;
|
||||
/* Read pointer */
|
||||
static struct pcm_frame_header * ALIGNED_ATTR(4) pcmbuf_head IBSS_ATTR;
|
||||
/* Write pointer */
|
||||
static struct pcm_frame_header * ALIGNED_ATTR(4) pcmbuf_tail IBSS_ATTR;
|
||||
|
||||
/* Bytes */
|
||||
static ssize_t pcmbuf_curr_size IBSS_ATTR; /* Size of currently playing frame */
|
||||
static ssize_t pcmbuf_read IBSS_ATTR; /* Number of bytes read by DMA */
|
||||
static ssize_t pcmbuf_written IBSS_ATTR; /* Number of bytes written by source */
|
||||
static ssize_t pcmbuf_threshold IBSS_ATTR; /* Non-silence threshold */
|
||||
|
||||
/* Clock */
|
||||
static uint32_t clock_start IBSS_ATTR; /* Clock at playback start */
|
||||
static uint32_t volatile clock_tick IBSS_ATTR; /* Our base clock */
|
||||
static uint32_t volatile clock_time IBSS_ATTR; /* Timestamp adjusted */
|
||||
|
||||
static int pcm_skipped = 0;
|
||||
static int pcm_underruns = 0;
|
||||
|
||||
static unsigned int old_sampr = 0;
|
||||
|
||||
/* Small silence clip. ~5.80ms @ 44.1kHz */
|
||||
static int16_t silence[256*2] ALIGNED_ATTR(4) = { 0 };
|
||||
|
||||
/* Delete all buffer contents */
|
||||
static void pcm_reset_buffer(void)
|
||||
{
|
||||
pcmbuf_threshold = PCMOUT_PLAY_WM;
|
||||
pcmbuf_curr_size = pcmbuf_read = pcmbuf_written = 0;
|
||||
pcmbuf_head = pcmbuf_tail = pcm_buffer;
|
||||
pcm_skipped = pcm_underruns = 0;
|
||||
}
|
||||
|
||||
/* Advance a PCM buffer pointer by size bytes circularly */
|
||||
static inline void pcm_advance_buffer(struct pcm_frame_header **p,
|
||||
size_t size)
|
||||
{
|
||||
*p = SKIPBYTES(*p, size);
|
||||
if (*p >= pcmbuf_end)
|
||||
*p = SKIPBYTES(*p, -PCMOUT_BUFSIZE);
|
||||
}
|
||||
|
||||
/* Return physical space used */
|
||||
static inline ssize_t pcm_output_bytes_used(void)
|
||||
{
|
||||
return pcmbuf_written - pcmbuf_read; /* wrap-safe */
|
||||
}
|
||||
|
||||
/* Return physical space free */
|
||||
static inline ssize_t pcm_output_bytes_free(void)
|
||||
{
|
||||
return PCMOUT_BUFSIZE - pcm_output_bytes_used();
|
||||
}
|
||||
|
||||
/* Audio DMA handler */
|
||||
static void get_more(const void **start, size_t *size)
|
||||
{
|
||||
ssize_t sz;
|
||||
|
||||
/* Free-up the last frame played frame if any */
|
||||
pcmbuf_read += pcmbuf_curr_size;
|
||||
pcmbuf_curr_size = 0;
|
||||
|
||||
sz = pcm_output_bytes_used();
|
||||
|
||||
if (sz > pcmbuf_threshold)
|
||||
{
|
||||
pcmbuf_threshold = PCMOUT_LOW_WM;
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint32_t time = pcmbuf_head->time;
|
||||
int32_t offset = time - clock_time;
|
||||
|
||||
sz = pcmbuf_head->size;
|
||||
|
||||
if (sz < (ssize_t)(PCM_HDR_SIZE + 4) ||
|
||||
(sz & 3) != 0)
|
||||
{
|
||||
/* Just show a warning about this - will never happen
|
||||
* without a corrupted buffer */
|
||||
DEBUGF("get_more: invalid size (%ld)\n", (long)sz);
|
||||
}
|
||||
|
||||
if (offset < -100*CLOCK_RATE/1000)
|
||||
{
|
||||
/* Frame more than 100ms late - drop it */
|
||||
pcm_advance_buffer(&pcmbuf_head, sz);
|
||||
pcmbuf_read += sz;
|
||||
pcm_skipped++;
|
||||
if (pcm_output_bytes_used() > 0)
|
||||
continue;
|
||||
|
||||
/* Ran out so revert to default watermark */
|
||||
pcmbuf_threshold = PCMOUT_PLAY_WM;
|
||||
pcm_underruns++;
|
||||
}
|
||||
else if (offset < 100*CLOCK_RATE/1000)
|
||||
{
|
||||
/* Frame less than 100ms early - play it */
|
||||
struct pcm_frame_header *head = pcmbuf_head;
|
||||
|
||||
pcm_advance_buffer(&pcmbuf_head, sz);
|
||||
pcmbuf_curr_size = sz;
|
||||
|
||||
sz -= PCM_HDR_SIZE;
|
||||
|
||||
/* Audio is time master - keep clock synchronized */
|
||||
clock_time = time + (sz >> 2);
|
||||
|
||||
/* Update base clock */
|
||||
clock_tick += sz >> 2;
|
||||
|
||||
*start = head->data;
|
||||
*size = sz;
|
||||
return;
|
||||
}
|
||||
/* Frame will be dropped - play silence clip */
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ran out so revert to default watermark */
|
||||
if (pcmbuf_threshold == PCMOUT_LOW_WM)
|
||||
pcm_underruns++;
|
||||
|
||||
pcmbuf_threshold = PCMOUT_PLAY_WM;
|
||||
}
|
||||
|
||||
/* Keep clock going at all times */
|
||||
clock_time += sizeof (silence) / 4;
|
||||
clock_tick += sizeof (silence) / 4;
|
||||
|
||||
*start = silence;
|
||||
*size = sizeof (silence);
|
||||
|
||||
if (sz < 0)
|
||||
pcmbuf_read = pcmbuf_written;
|
||||
}
|
||||
|
||||
/** Public interface **/
|
||||
|
||||
/* Return a buffer pointer if at least size bytes are available and if so,
|
||||
* give the actual free space */
|
||||
void * pcm_output_get_buffer(ssize_t *size)
|
||||
{
|
||||
ssize_t sz = *size;
|
||||
ssize_t free = pcm_output_bytes_free() - PCM_HDR_SIZE;
|
||||
|
||||
if (sz >= 0 && free >= sz)
|
||||
{
|
||||
*size = free; /* return actual free space (- header) */
|
||||
return pcmbuf_tail->data;
|
||||
}
|
||||
|
||||
/* Leave *size alone so caller doesn't have to reinit */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Commit the buffer returned by pcm_ouput_get_buffer; timestamp is PCM
|
||||
* clock time units, not video format time units */
|
||||
bool pcm_output_commit_data(ssize_t size, uint32_t timestamp)
|
||||
{
|
||||
if (size <= 0 || (size & 3))
|
||||
return false; /* invalid */
|
||||
|
||||
size += PCM_HDR_SIZE;
|
||||
|
||||
if (size > pcm_output_bytes_free())
|
||||
return false; /* too big */
|
||||
|
||||
pcmbuf_tail->size = size;
|
||||
pcmbuf_tail->time = timestamp;
|
||||
|
||||
pcm_advance_buffer(&pcmbuf_tail, size);
|
||||
pcmbuf_written += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns 'true' if the buffer is completely empty */
|
||||
bool pcm_output_empty(void)
|
||||
{
|
||||
return pcm_output_bytes_used() <= 0;
|
||||
}
|
||||
|
||||
/* Flushes the buffer - clock keeps counting */
|
||||
void pcm_output_flush(void)
|
||||
{
|
||||
rb->pcm_play_lock();
|
||||
|
||||
enum channel_status status = rb->mixer_channel_status(MPEG_PCM_CHANNEL);
|
||||
|
||||
/* Stop PCM to clear current buffer */
|
||||
if (status != CHANNEL_STOPPED)
|
||||
rb->mixer_channel_stop(MPEG_PCM_CHANNEL);
|
||||
|
||||
rb->pcm_play_unlock();
|
||||
|
||||
pcm_reset_buffer();
|
||||
|
||||
/* Restart if playing state was current */
|
||||
if (status == CHANNEL_PLAYING)
|
||||
rb->mixer_channel_play_data(MPEG_PCM_CHANNEL,
|
||||
get_more, NULL, 0);
|
||||
}
|
||||
|
||||
/* Seek the reference clock to the specified time - next audio data ready to
|
||||
go to DMA should be on the buffer with the same time index or else the PCM
|
||||
buffer should be empty */
|
||||
void pcm_output_set_clock(uint32_t time)
|
||||
{
|
||||
rb->pcm_play_lock();
|
||||
|
||||
clock_start = time;
|
||||
clock_tick = time;
|
||||
clock_time = time;
|
||||
|
||||
rb->pcm_play_unlock();
|
||||
}
|
||||
|
||||
/* Return the clock as synchronized by audio frame timestamps */
|
||||
uint32_t pcm_output_get_clock(void)
|
||||
{
|
||||
uint32_t time, rem;
|
||||
|
||||
/* Reread if data race detected - rem will be 0 if driver hasn't yet
|
||||
* updated to the new buffer size. Also be sure pcm state doesn't
|
||||
* cause indefinite loop.
|
||||
*
|
||||
* FYI: NOT scrutinized for rd/wr reordering on different cores. */
|
||||
do
|
||||
{
|
||||
time = clock_time;
|
||||
rem = rb->mixer_channel_get_bytes_waiting(MPEG_PCM_CHANNEL) >> 2;
|
||||
}
|
||||
while (UNLIKELY(time != clock_time ||
|
||||
(rem == 0 &&
|
||||
rb->mixer_channel_status(MPEG_PCM_CHANNEL) == CHANNEL_PLAYING))
|
||||
);
|
||||
|
||||
return time - rem;
|
||||
|
||||
}
|
||||
|
||||
/* Return the raw clock as counted from the last pcm_output_set_clock
|
||||
* call */
|
||||
uint32_t pcm_output_get_ticks(uint32_t *start)
|
||||
{
|
||||
uint32_t tick, rem;
|
||||
|
||||
/* Same procedure as pcm_output_get_clock */
|
||||
do
|
||||
{
|
||||
tick = clock_tick;
|
||||
rem = rb->mixer_channel_get_bytes_waiting(MPEG_PCM_CHANNEL) >> 2;
|
||||
}
|
||||
while (UNLIKELY(tick != clock_tick ||
|
||||
(rem == 0 &&
|
||||
rb->mixer_channel_status(MPEG_PCM_CHANNEL) == CHANNEL_PLAYING))
|
||||
);
|
||||
|
||||
if (start)
|
||||
*start = clock_start;
|
||||
|
||||
return tick - rem;
|
||||
}
|
||||
|
||||
/* Pauses/Starts pcm playback - and the clock */
|
||||
void pcm_output_play_pause(bool play)
|
||||
{
|
||||
rb->pcm_play_lock();
|
||||
|
||||
if (rb->mixer_channel_status(MPEG_PCM_CHANNEL) != CHANNEL_STOPPED)
|
||||
{
|
||||
rb->mixer_channel_play_pause(MPEG_PCM_CHANNEL, play);
|
||||
rb->pcm_play_unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
rb->pcm_play_unlock();
|
||||
|
||||
if (play)
|
||||
{
|
||||
rb->mixer_channel_set_amplitude(MPEG_PCM_CHANNEL, MIX_AMP_UNITY);
|
||||
rb->mixer_channel_play_data(MPEG_PCM_CHANNEL,
|
||||
get_more, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Stops all playback and resets the clock */
|
||||
void pcm_output_stop(void)
|
||||
{
|
||||
rb->pcm_play_lock();
|
||||
|
||||
if (rb->mixer_channel_status(MPEG_PCM_CHANNEL) != CHANNEL_STOPPED)
|
||||
rb->mixer_channel_stop(MPEG_PCM_CHANNEL);
|
||||
|
||||
rb->pcm_play_unlock();
|
||||
|
||||
pcm_output_flush();
|
||||
pcm_output_set_clock(0);
|
||||
}
|
||||
|
||||
/* Drains any data if the start threshold hasn't been reached */
|
||||
void pcm_output_drain(void)
|
||||
{
|
||||
rb->pcm_play_lock();
|
||||
pcmbuf_threshold = PCMOUT_LOW_WM;
|
||||
rb->pcm_play_unlock();
|
||||
}
|
||||
|
||||
bool pcm_output_init(void)
|
||||
{
|
||||
pcm_buffer = mpeg_malloc(PCMOUT_ALLOC_SIZE, MPEG_ALLOC_PCMOUT);
|
||||
if (pcm_buffer == NULL)
|
||||
return false;
|
||||
|
||||
pcmbuf_end = SKIPBYTES(pcm_buffer, PCMOUT_BUFSIZE);
|
||||
|
||||
pcm_reset_buffer();
|
||||
|
||||
#if INPUT_SRC_CAPS != 0
|
||||
/* Select playback */
|
||||
rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
|
||||
rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
|
||||
#endif
|
||||
|
||||
#if SILENCE_TEST_TONE
|
||||
/* Make the silence clip a square wave */
|
||||
const int16_t silence_amp = INT16_MAX / 16;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < ARRAYLEN(silence); i += 2)
|
||||
{
|
||||
if (i < ARRAYLEN(silence)/2)
|
||||
{
|
||||
silence[i] = silence_amp;
|
||||
silence[i+1] = silence_amp;
|
||||
}
|
||||
else
|
||||
{
|
||||
silence[i] = -silence_amp;
|
||||
silence[i+1] = -silence_amp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
old_sampr = rb->mixer_get_frequency();
|
||||
rb->mixer_set_frequency(CLOCK_RATE);
|
||||
rb->pcmbuf_fade(false, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pcm_output_exit(void)
|
||||
{
|
||||
rb->pcmbuf_fade(false, false);
|
||||
if (old_sampr != 0)
|
||||
rb->mixer_set_frequency(old_sampr);
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* PCM output buffer declarations
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef PCM_OUTPUT_H
|
||||
#define PCM_OUTPUT_H
|
||||
|
||||
#define PCM_HDR_SIZE (sizeof (struct pcm_frame_header))
|
||||
struct pcm_frame_header /* Header added to pcm data every time a decoded
|
||||
audio frame is sent out */
|
||||
{
|
||||
uint32_t size; /* size of this frame - including header */
|
||||
uint32_t time; /* timestamp for this frame in audio ticks */
|
||||
unsigned char data[]; /* open array of audio data */
|
||||
} ALIGNED_ATTR(4);
|
||||
|
||||
bool pcm_output_init(void);
|
||||
void pcm_output_exit(void);
|
||||
void pcm_output_flush(void);
|
||||
void pcm_output_set_clock(uint32_t time);
|
||||
uint32_t pcm_output_get_clock(void);
|
||||
uint32_t pcm_output_get_ticks(uint32_t *start);
|
||||
void pcm_output_play_pause(bool play);
|
||||
void pcm_output_stop(void);
|
||||
void pcm_output_drain(void);
|
||||
void * pcm_output_get_buffer(ssize_t *size);
|
||||
bool pcm_output_commit_data(ssize_t size, uint32_t timestamp);
|
||||
bool pcm_output_empty(void);
|
||||
|
||||
#endif /* PCM_OUTPUT_H */
|
File diff suppressed because it is too large
Load diff
|
@ -1,168 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* AV stream manager decalarations
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef STREAM_MGR_H
|
||||
#define STREAM_MGR_H
|
||||
|
||||
/* Basic media control interface - this handles state changes and stream
|
||||
* coordination with assistance from the parser */
|
||||
struct stream_mgr
|
||||
{
|
||||
unsigned int thread; /* Playback control thread */
|
||||
struct event_queue *q; /* event queue for control thread */
|
||||
const char *filename; /* Current filename */
|
||||
uint32_t resume_time; /* The stream tick where playback was
|
||||
stopped (or started) */
|
||||
bool seeked; /* A seek happened and things must be
|
||||
resynced */
|
||||
int status; /* Current playback status */
|
||||
void *strl[MPEGPLAYER_MAX_STREAMS+1]; /* List of available streams */
|
||||
void *actl[MPEGPLAYER_MAX_STREAMS+1]; /* List of active streams */
|
||||
struct mutex str_mtx; /* Main stream manager mutex */
|
||||
struct mutex actl_mtx; /* Lock for current-streams list */
|
||||
union /* A place for reusable non-cacheable parameters */
|
||||
{
|
||||
struct vo_rect rc;
|
||||
struct stream_seek_data skd;
|
||||
} parms;
|
||||
};
|
||||
|
||||
extern struct stream_mgr stream_mgr SHAREDBSS_ATTR;
|
||||
|
||||
struct stream_window
|
||||
{
|
||||
off_t left, right;
|
||||
};
|
||||
|
||||
/** Interface for use by streams and other internal objects **/
|
||||
bool stream_get_window(struct stream_window *sw);
|
||||
void stream_clear_notify(struct stream *str, int for_msg);
|
||||
int str_next_data_not_ready(struct stream *str);
|
||||
/* Called by a stream to say it got its buffering notification */
|
||||
void str_data_notify_received(struct stream *str);
|
||||
void stream_add_stream(struct stream *str);
|
||||
void stream_remove_streams(void);
|
||||
|
||||
enum stream_events
|
||||
{
|
||||
__STREAM_EV_FIRST = STREAM_MESSAGE_LAST-1,
|
||||
STREAM_EV_COMPLETE,
|
||||
};
|
||||
|
||||
void stream_generate_event(struct stream *str, long id, intptr_t data);
|
||||
|
||||
/** Main control functions **/
|
||||
|
||||
/* Initialize the playback engine */
|
||||
int stream_init(void);
|
||||
|
||||
/* Close the playback engine */
|
||||
void stream_exit(void);
|
||||
|
||||
/* Open a new file */
|
||||
int stream_open(const char *filename);
|
||||
|
||||
/* Close the current file */
|
||||
int stream_close(void);
|
||||
|
||||
/* Plays from the current seekpoint if stopped */
|
||||
int stream_play(void);
|
||||
|
||||
/* Pauses playback if playing */
|
||||
int stream_pause(void);
|
||||
|
||||
/* Resumes playback if paused */
|
||||
int stream_resume(void);
|
||||
|
||||
/* Stops all streaming activity if playing or paused */
|
||||
int stream_stop(void);
|
||||
|
||||
/* Point stream at a particular time.
|
||||
* whence = one of SEEK_SET, SEEK_CUR, SEEK_END */
|
||||
int stream_seek(uint32_t time, int whence);
|
||||
|
||||
/* Show/Hide the video image at the current seekpoint */
|
||||
bool stream_show_vo(bool show);
|
||||
|
||||
/* Set the visible section of video */
|
||||
void stream_vo_set_clip(const struct vo_rect *rc);
|
||||
|
||||
/* Return current visible section of video */
|
||||
bool stream_vo_get_clip(struct vo_rect *rc);
|
||||
|
||||
#ifndef HAVE_LCD_COLOR
|
||||
void stream_gray_show(bool show);
|
||||
#endif
|
||||
|
||||
/* Display thumbnail of the current seekpoint */
|
||||
bool stream_display_thumb(const struct vo_rect *rc);
|
||||
|
||||
/* Draw the frame at the current position */
|
||||
bool stream_draw_frame(bool no_prepare);
|
||||
|
||||
/* Return video dimensions */
|
||||
bool stream_vo_get_size(struct vo_ext *sz);
|
||||
|
||||
/* Returns the resume time in timestamp ticks */
|
||||
uint32_t stream_get_resume_time(void);
|
||||
|
||||
/* Returns stream_get_time if no seek is pending or else the
|
||||
last time give to seek */
|
||||
uint32_t stream_get_seek_time(uint32_t *start);
|
||||
|
||||
/* Return the absolute stream time in clock ticks - adjusted by
|
||||
* master clock stream via audio timestamps */
|
||||
static inline uint32_t stream_get_time(void)
|
||||
{ return pcm_output_get_clock(); }
|
||||
|
||||
/* Return the absolute clock time in clock ticks - unadjusted */
|
||||
static inline uint32_t stream_get_ticks(uint32_t *start)
|
||||
{ return pcm_output_get_ticks(start); }
|
||||
|
||||
/* Returns the current playback status */
|
||||
static inline int stream_status(void)
|
||||
{ return stream_mgr.status; }
|
||||
|
||||
/* Wait for a state transistion to complete */
|
||||
void stream_wait_status(void);
|
||||
|
||||
/* Returns the playback length of the stream */
|
||||
static inline uint32_t stream_get_duration(void)
|
||||
{ return str_parser.duration; }
|
||||
|
||||
static inline bool stream_can_seek(void)
|
||||
{ return parser_can_seek(); }
|
||||
|
||||
static inline void stream_video_stats(struct video_output_stats *s)
|
||||
{ video_thread_get_stats(s); }
|
||||
|
||||
bool stream_set_callback(long id, void * fn);
|
||||
|
||||
/* Keep the disk spinning (for seeking and browsing) */
|
||||
static inline void stream_keep_disk_active(void)
|
||||
{
|
||||
#ifdef HAVE_DISK_STORAGE
|
||||
rb->storage_spin();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* STREAM_MGR_H */
|
|
@ -1,201 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Declarations for stream-specific threading
|
||||
*
|
||||
* Copyright (c) 2007 Michael Sevakis
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef STREAM_THREAD_H
|
||||
#define STREAM_THREAD_H
|
||||
|
||||
#define PKT_HAS_TS 0x1
|
||||
|
||||
/* Stream header which is the minimum to receive asynchronous buffering
|
||||
* notifications.
|
||||
* Layed-out to allow streaming access after random-access parsing */
|
||||
struct stream_hdr
|
||||
{
|
||||
struct event_queue *q; /* Communication queue - separate to allow it
|
||||
to be placed in another section */
|
||||
off_t win_left; /* Left position within data stream */
|
||||
union
|
||||
{
|
||||
off_t win_right; /* Right position within data stream */
|
||||
off_t pos; /* Start/current position for random-access read */
|
||||
};
|
||||
off_t limit; /* Limit for random-access read */
|
||||
};
|
||||
|
||||
struct stream
|
||||
{
|
||||
struct stream_hdr hdr; /* Base stream data */
|
||||
unsigned int thread; /* Stream's thread */
|
||||
uint8_t* curr_packet; /* Current stream packet beginning */
|
||||
uint8_t* curr_packet_end; /* Current stream packet end */
|
||||
int state; /* State machine parsing mode */
|
||||
uint32_t start_pts; /* First timestamp for stream */
|
||||
uint32_t end_pts; /* Last timestamp for stream */
|
||||
uint32_t pts; /* Last presentation timestamp */
|
||||
uint32_t pkt_flags; /* PKT_* flags */
|
||||
unsigned id; /* Stream identifier */
|
||||
};
|
||||
|
||||
#define STR_FROM_HDR(sh) ((struct stream *)(sh))
|
||||
|
||||
/* Make sure there there is always enough data buffered ahead for
|
||||
* the worst possible case - regardless of whether a valid stream
|
||||
* would actually produce that */
|
||||
#define MIN_BUFAHEAD (21+65535+6+65535+6) /* 131103 */
|
||||
|
||||
/* States that a stream's thread assumes internally */
|
||||
enum thread_states
|
||||
{
|
||||
/* Stream thread... */
|
||||
TSTATE_INIT = 0, /* is initialized and primed */
|
||||
TSTATE_DATA, /* is awaiting data to be available */
|
||||
TSTATE_BUFFERING, /* is buffering data */
|
||||
TSTATE_EOS, /* has hit the end of data */
|
||||
TSTATE_DECODE, /* is in a decoding state */
|
||||
TSTATE_RENDER, /* is in a rendering state */
|
||||
TSTATE_RENDER_WAIT, /* is waiting to render */
|
||||
};
|
||||
|
||||
/* Commands that streams respond to */
|
||||
enum stream_message
|
||||
{
|
||||
STREAM_NULL = 0, /* A NULL message for whatever reason -
|
||||
usually ignored */
|
||||
STREAM_PLAY, /* Start playback at current position */
|
||||
STREAM_PAUSE, /* Stop playing and await further commands */
|
||||
STREAM_RESET, /* Reset the stream for a discontinuity */
|
||||
STREAM_STOP, /* Stop stream - requires a reset later */
|
||||
STREAM_SEEK, /* Seek the current stream to a new location */
|
||||
STREAM_OPEN, /* Open a new file */
|
||||
STREAM_CLOSE, /* Close the current file */
|
||||
STREAM_QUIT, /* Exit the stream and thread */
|
||||
STREAM_NEEDS_SYNC, /* Need to sync before stream decoding? */
|
||||
STREAM_SYNC, /* Sync to the specified time from some key point */
|
||||
STREAM_FIND_END_TIME, /* Get the exact end time of an elementary
|
||||
* stream - ie. time just after last frame is finished */
|
||||
/* Disk buffer */
|
||||
STREAM_DISK_BUF_FIRST,
|
||||
DISK_BUF_DATA_NOTIFY = STREAM_DISK_BUF_FIRST,
|
||||
DISK_BUF_CLEAR_DATA_NOTIFY, /* Cancel pending data notification */
|
||||
DISK_BUF_CACHE_RANGE, /* Cache a range of the file in the buffer */
|
||||
/* Audio stream */
|
||||
STREAM_AUDIO_FIRST,
|
||||
/* Video stream */
|
||||
STREAM_VIDEO_FIRST,
|
||||
VIDEO_DISPLAY_SHOW = STREAM_VIDEO_FIRST, /* Show/hide video output */
|
||||
VIDEO_DISPLAY_IS_VISIBLE, /* Is the video output visible? */
|
||||
VIDEO_GET_SIZE, /* Get the video dimensions */
|
||||
VIDEO_PRINT_FRAME, /* Print the frame at the current position */
|
||||
VIDEO_PRINT_THUMBNAIL, /* Print a thumbnail of the current position */
|
||||
VIDEO_SET_CLIP_RECT, /* Set the visible video area */
|
||||
VIDEO_GET_CLIP_RECT, /* Return the visible video area */
|
||||
VIDEO_SET_POST_FRAME_CALLBACK, /* Set a callback after frame is drawn */
|
||||
STREAM_MESSAGE_LAST,
|
||||
};
|
||||
|
||||
/* Data parameter for STREAM_SEEK */
|
||||
struct stream_seek_data
|
||||
{
|
||||
uint32_t time; /* Time to seek to/by */
|
||||
int whence; /* Specification of relationship to current position/file */
|
||||
};
|
||||
|
||||
/* Data parameter for STREAM_SYNC */
|
||||
struct str_sync_data
|
||||
{
|
||||
uint32_t time; /* Time to sync to */
|
||||
struct stream_scan sk; /* Specification of start/limits/direction */
|
||||
};
|
||||
|
||||
/* Stream status codes - not eqivalent to thread states */
|
||||
enum stream_status
|
||||
{
|
||||
/* Stream status is... */
|
||||
STREAM_DATA_END = -4, /* Stream has ended */
|
||||
STREAM_DATA_NOT_READY = -3, /* Data was not available yet */
|
||||
STREAM_UNSUPPORTED = -2, /* Format is unsupported */
|
||||
STREAM_ERROR = -1, /* some kind of error - quit it or reset it */
|
||||
STREAM_OK = 0, /* General inequality for success >= is OK, < error */
|
||||
STREAM_STOPPED = 0, /* stopped and awaiting commands - send STREAM_INIT */
|
||||
STREAM_PLAYING, /* playing and rendering its data */
|
||||
STREAM_PAUSED, /* paused and awaiting commands */
|
||||
/* Other status codes (> STREAM_OK) */
|
||||
STREAM_MATCH, /* A good match was found */
|
||||
STREAM_PERFECT_MATCH, /* Exactly what was wanted was found or
|
||||
no better match is possible */
|
||||
STREAM_NOT_FOUND, /* Match not found */
|
||||
};
|
||||
|
||||
/* Clip time to range for a particular stream */
|
||||
static inline uint32_t clip_time(struct stream *str, uint32_t time)
|
||||
{
|
||||
if (time < str->start_pts)
|
||||
time = str->start_pts;
|
||||
else if (time >= str->end_pts)
|
||||
time = str->end_pts;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
extern struct stream video_str IBSS_ATTR;
|
||||
extern struct stream audio_str IBSS_ATTR;
|
||||
|
||||
bool video_thread_init(void);
|
||||
void video_thread_exit(void);
|
||||
|
||||
struct video_output_stats
|
||||
{
|
||||
int num_drawn; /* Number of frames drawn since reset */
|
||||
int num_skipped; /* Number of frames skipped since reset */
|
||||
int fps; /* fps rate in 100ths of a frame per second */
|
||||
};
|
||||
|
||||
void video_thread_get_stats(struct video_output_stats *s);
|
||||
|
||||
bool audio_thread_init(void);
|
||||
void audio_thread_exit(void);
|
||||
|
||||
|
||||
/* Some queue function wrappers to keep things clean-ish */
|
||||
|
||||
/* For stream use only */
|
||||
static inline bool str_have_msg(struct stream *str)
|
||||
{ return !rb->queue_empty(str->hdr.q); }
|
||||
|
||||
static inline void str_get_msg(struct stream *str, struct queue_event *ev)
|
||||
{ rb->queue_wait(str->hdr.q, ev); }
|
||||
|
||||
static inline void str_get_msg_w_tmo(struct stream *str, struct queue_event *ev,
|
||||
int timeout)
|
||||
{ rb->queue_wait_w_tmo(str->hdr.q, ev, timeout); }
|
||||
|
||||
static inline void str_reply_msg(struct stream *str, intptr_t reply)
|
||||
{ rb->queue_reply(str->hdr.q, reply); }
|
||||
|
||||
/* Public use */
|
||||
static inline intptr_t str_send_msg(struct stream *str, long id, intptr_t data)
|
||||
{ return rb->queue_send(str->hdr.q, id, data); }
|
||||
|
||||
static inline void str_post_msg(struct stream *str, long id, intptr_t data)
|
||||
{ rb->queue_post(str->hdr.q, id, data); }
|
||||
|
||||
#endif /* STREAM_THREAD_H */
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* video_out.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
|
||||
*
|
||||
* $Id$
|
||||
* libmpeg2 sync history:
|
||||
* 2008-07-01 - CVS revision 1.22
|
||||
*/
|
||||
|
||||
#ifndef VIDEO_OUT_H
|
||||
#define VIDEO_OUT_H
|
||||
|
||||
#if LCD_WIDTH >= LCD_HEIGHT
|
||||
#define SCREEN_WIDTH LCD_WIDTH
|
||||
#define SCREEN_HEIGHT LCD_HEIGHT
|
||||
#define LCD_LANDSCAPE
|
||||
#else /* Assume the screen is rotated on portrait LCDs */
|
||||
#define SCREEN_WIDTH LCD_HEIGHT
|
||||
#define SCREEN_HEIGHT LCD_WIDTH
|
||||
#define LCD_PORTRAIT
|
||||
#endif
|
||||
|
||||
/* Structure to hold width and height values */
|
||||
struct vo_ext
|
||||
{
|
||||
int w, h;
|
||||
};
|
||||
|
||||
/* Structure that defines a rectangle by its edges */
|
||||
struct vo_rect
|
||||
{
|
||||
int l, t, r, b;
|
||||
};
|
||||
|
||||
void vo_draw_frame (uint8_t * const * buf);
|
||||
bool vo_draw_frame_thumb (uint8_t * const * buf,
|
||||
const struct vo_rect *rc);
|
||||
bool vo_init (void);
|
||||
bool vo_show (bool show);
|
||||
bool vo_is_visible(void);
|
||||
void vo_setup (const mpeg2_sequence_t * sequence);
|
||||
void vo_set_clip_rect(const struct vo_rect *rc);
|
||||
bool vo_get_clip_rect(struct vo_rect *rc);
|
||||
void vo_dimensions(struct vo_ext *sz);
|
||||
void vo_cleanup (void);
|
||||
void vo_set_post_draw_callback(void (*cb)(void));
|
||||
|
||||
#if NUM_CORES > 1
|
||||
void vo_lock(void);
|
||||
void vo_unlock(void);
|
||||
#else
|
||||
static inline void vo_lock(void) {}
|
||||
static inline void vo_unlock(void) {}
|
||||
#endif
|
||||
|
||||
/* Sets all coordinates of a vo_rect to 0 */
|
||||
void vo_rect_clear(struct vo_rect *rc);
|
||||
/* Returns true if left >= right or top >= bottom */
|
||||
bool vo_rect_empty(const struct vo_rect *rc);
|
||||
/* Initializes a vo_rect using upper-left corner and extents */
|
||||
void vo_rect_set_ext(struct vo_rect *rc, int x, int y,
|
||||
int width, int height);
|
||||
/* Query if two rectangles intersect
|
||||
* If either are empty returns false */
|
||||
bool vo_rects_intersect(const struct vo_rect *rc1,
|
||||
const struct vo_rect *rc2);
|
||||
|
||||
/* Intersect two rectangles
|
||||
* Resulting rectangle is placed in rc_dst.
|
||||
* rc_dst is set to empty if they don't intersect.
|
||||
* Empty source rectangles do not intersect any rectangle.
|
||||
* rc_dst may be the same structure as rc1 or rc2.
|
||||
* Returns true if the resulting rectangle is not empty. */
|
||||
bool vo_rect_intersect(struct vo_rect *rc_dst,
|
||||
const struct vo_rect *rc1,
|
||||
const struct vo_rect *rc2);
|
||||
|
||||
bool vo_rect_union(struct vo_rect *rc_dst,
|
||||
const struct vo_rect *rc1,
|
||||
const struct vo_rect *rc2);
|
||||
|
||||
void vo_rect_offset(struct vo_rect *rc, int dx, int dy);
|
||||
|
||||
#endif /* VIDEO_OUT_H */
|
|
@ -1,576 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* mpegplayer video output routines
|
||||
*
|
||||
* 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "libmpeg2/mpeg2dec_config.h"
|
||||
|
||||
#include "plugin.h"
|
||||
#include "mpegplayer.h"
|
||||
|
||||
#define VO_NON_NULL_RECT 0x1
|
||||
#define VO_VISIBLE 0x2
|
||||
|
||||
struct vo_data
|
||||
{
|
||||
int image_width;
|
||||
int image_height;
|
||||
int image_chroma_x;
|
||||
int image_chroma_y;
|
||||
int display_width;
|
||||
int display_height;
|
||||
int output_x;
|
||||
int output_y;
|
||||
int output_width;
|
||||
int output_height;
|
||||
unsigned flags;
|
||||
struct vo_rect rc_vid;
|
||||
struct vo_rect rc_clip;
|
||||
void (*post_draw_callback)(void);
|
||||
};
|
||||
|
||||
#if NUM_CORES > 1
|
||||
/* Cache aligned and padded to avoid clobbering other processors' cacheable
|
||||
* data */
|
||||
static union {
|
||||
uint8_t __vo_data[CACHEALIGN_UP(sizeof(struct vo_data))];
|
||||
struct vo_data vo;
|
||||
} vo_raw CACHEALIGN_ATTR;
|
||||
#define vo vo_raw.vo
|
||||
#else
|
||||
static struct vo_data vo;
|
||||
#endif
|
||||
|
||||
#if NUM_CORES > 1
|
||||
static struct mutex vo_mtx SHAREDBSS_ATTR;
|
||||
#endif
|
||||
|
||||
static inline void video_lock_init(void)
|
||||
{
|
||||
#if NUM_CORES > 1
|
||||
rb->mutex_init(&vo_mtx);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void video_lock(void)
|
||||
{
|
||||
#if NUM_CORES > 1
|
||||
rb->mutex_lock(&vo_mtx);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void video_unlock(void)
|
||||
{
|
||||
#if NUM_CORES > 1
|
||||
rb->mutex_unlock(&vo_mtx);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Draw a black rectangle if no video frame is available */
|
||||
static void vo_draw_black(struct vo_rect *rc)
|
||||
{
|
||||
int foreground;
|
||||
int x, y, w, h;
|
||||
|
||||
video_lock();
|
||||
|
||||
foreground = mylcd_get_foreground();
|
||||
|
||||
mylcd_set_foreground(MYLCD_BLACK);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
x = rc->l;
|
||||
y = rc->t;
|
||||
w = rc->r - rc->l;
|
||||
h = rc->b - rc->t;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if LCD_WIDTH >= LCD_HEIGHT
|
||||
x = vo.output_x;
|
||||
y = vo.output_y;
|
||||
w = vo.output_width;
|
||||
h = vo.output_height;
|
||||
#else
|
||||
x = LCD_WIDTH - vo.output_height - vo.output_y;
|
||||
y = vo.output_x;
|
||||
w = vo.output_height;
|
||||
h = vo.output_width;
|
||||
#endif
|
||||
}
|
||||
|
||||
mylcd_fillrect(x, y, w, h);
|
||||
mylcd_update_rect(x, y, w, h);
|
||||
|
||||
mylcd_set_foreground(foreground);
|
||||
|
||||
video_unlock();
|
||||
}
|
||||
|
||||
static inline void yuv_blit(uint8_t * const * buf, int src_x, int src_y,
|
||||
int stride, int x, int y, int width, int height)
|
||||
{
|
||||
video_lock();
|
||||
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
rb->lcd_blit_yuv(buf, src_x, src_y, stride, x, y , width, height);
|
||||
#else
|
||||
grey_ub_gray_bitmap_part(buf[0], src_x, src_y, stride, x, y, width, height);
|
||||
#endif
|
||||
|
||||
video_unlock();
|
||||
}
|
||||
|
||||
void vo_draw_frame(uint8_t * const * buf)
|
||||
{
|
||||
if ((vo.flags & (VO_NON_NULL_RECT | VO_VISIBLE)) !=
|
||||
(VO_NON_NULL_RECT | VO_VISIBLE))
|
||||
{
|
||||
/* Frame is hidden - either by being set invisible or is clipped
|
||||
* away - copout */
|
||||
DEBUGF("vo hidden\n");
|
||||
}
|
||||
else if (buf == NULL)
|
||||
{
|
||||
/* No frame exists - draw black */
|
||||
vo_draw_black(NULL);
|
||||
DEBUGF("vo no frame\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
yuv_blit(buf, 0, 0, vo.image_width,
|
||||
vo.output_x, vo.output_y, vo.output_width,
|
||||
vo.output_height);
|
||||
}
|
||||
|
||||
if (vo.post_draw_callback)
|
||||
vo.post_draw_callback();
|
||||
}
|
||||
|
||||
static inline void vo_rect_clear_inl(struct vo_rect *rc)
|
||||
{
|
||||
rc->l = rc->t = rc->r = rc->b = 0;
|
||||
}
|
||||
|
||||
static inline bool vo_rect_empty_inl(const struct vo_rect *rc)
|
||||
{
|
||||
return rc == NULL || rc->l >= rc->r || rc->t >= rc->b;
|
||||
}
|
||||
|
||||
static inline bool vo_rects_intersect_inl(const struct vo_rect *rc1,
|
||||
const struct vo_rect *rc2)
|
||||
{
|
||||
return !vo_rect_empty_inl(rc1) &&
|
||||
!vo_rect_empty_inl(rc2) &&
|
||||
rc1->l < rc2->r && rc1->r > rc2->l &&
|
||||
rc1->t < rc2->b && rc1->b > rc2->t;
|
||||
}
|
||||
|
||||
/* Sets all coordinates of a vo_rect to 0 */
|
||||
void vo_rect_clear(struct vo_rect *rc)
|
||||
{
|
||||
vo_rect_clear_inl(rc);
|
||||
}
|
||||
|
||||
/* Returns true if left >= right or top >= bottom */
|
||||
bool vo_rect_empty(const struct vo_rect *rc)
|
||||
{
|
||||
return vo_rect_empty_inl(rc);
|
||||
}
|
||||
|
||||
/* Initializes a vo_rect using upper-left corner and extents */
|
||||
void vo_rect_set_ext(struct vo_rect *rc, int x, int y,
|
||||
int width, int height)
|
||||
{
|
||||
rc->l = x;
|
||||
rc->t = y;
|
||||
rc->r = x + width;
|
||||
rc->b = y + height;
|
||||
}
|
||||
|
||||
/* Query if two rectangles intersect */
|
||||
bool vo_rects_intersect(const struct vo_rect *rc1,
|
||||
const struct vo_rect *rc2)
|
||||
{
|
||||
return vo_rects_intersect_inl(rc1, rc2);
|
||||
}
|
||||
|
||||
/* Intersect two rectangles, placing the result in rc_dst */
|
||||
bool vo_rect_intersect(struct vo_rect *rc_dst,
|
||||
const struct vo_rect *rc1,
|
||||
const struct vo_rect *rc2)
|
||||
{
|
||||
if (rc_dst != NULL)
|
||||
{
|
||||
if (vo_rects_intersect_inl(rc1, rc2))
|
||||
{
|
||||
rc_dst->l = MAX(rc1->l, rc2->l);
|
||||
rc_dst->r = MIN(rc1->r, rc2->r);
|
||||
rc_dst->t = MAX(rc1->t, rc2->t);
|
||||
rc_dst->b = MIN(rc1->b, rc2->b);
|
||||
return true;
|
||||
}
|
||||
|
||||
vo_rect_clear_inl(rc_dst);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool vo_rect_union(struct vo_rect *rc_dst,
|
||||
const struct vo_rect *rc1,
|
||||
const struct vo_rect *rc2)
|
||||
{
|
||||
if (rc_dst != NULL)
|
||||
{
|
||||
if (!vo_rect_empty_inl(rc1))
|
||||
{
|
||||
if (!vo_rect_empty_inl(rc2))
|
||||
{
|
||||
rc_dst->l = MIN(rc1->l, rc2->l);
|
||||
rc_dst->t = MIN(rc1->t, rc2->t);
|
||||
rc_dst->r = MAX(rc1->r, rc2->r);
|
||||
rc_dst->b = MAX(rc1->b, rc2->b);
|
||||
}
|
||||
else
|
||||
{
|
||||
*rc_dst = *rc1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (!vo_rect_empty_inl(rc2))
|
||||
{
|
||||
*rc_dst = *rc2;
|
||||
return true;
|
||||
}
|
||||
|
||||
vo_rect_clear_inl(rc_dst);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void vo_rect_offset(struct vo_rect *rc, int dx, int dy)
|
||||
{
|
||||
rc->l += dx;
|
||||
rc->t += dy;
|
||||
rc->r += dx;
|
||||
rc->b += dy;
|
||||
}
|
||||
|
||||
/* Shink or stretch each axis - rotate counter-clockwise to retain upright
|
||||
* orientation on rotated displays (they rotate clockwise) */
|
||||
void stretch_image_plane(const uint8_t * src, uint8_t *dst, int stride,
|
||||
int src_w, int src_h, int dst_w, int dst_h)
|
||||
{
|
||||
uint8_t *dst_end = dst + dst_w*dst_h;
|
||||
|
||||
#if LCD_WIDTH >= LCD_HEIGHT
|
||||
int src_w2 = src_w*2; /* 2x dimensions (for rounding before division) */
|
||||
int dst_w2 = dst_w*2;
|
||||
int src_h2 = src_h*2;
|
||||
int dst_h2 = dst_h*2;
|
||||
int qw = src_w2 / dst_w2; /* src-dst width ratio quotient */
|
||||
int rw = src_w2 - qw*dst_w2; /* src-dst width ratio remainder */
|
||||
int qh = src_h2 / dst_h2; /* src-dst height ratio quotient */
|
||||
int rh = src_h2 - qh*dst_h2; /* src-dst height ratio remainder */
|
||||
int dw = dst_w; /* Width error accumulator */
|
||||
int dh = dst_h; /* Height error accumulator */
|
||||
#else
|
||||
int src_w2 = src_w*2;
|
||||
int dst_w2 = dst_h*2;
|
||||
int src_h2 = src_h*2;
|
||||
int dst_h2 = dst_w*2;
|
||||
int qw = src_h2 / dst_w2;
|
||||
int rw = src_h2 - qw*dst_w2;
|
||||
int qh = src_w2 / dst_h2;
|
||||
int rh = src_w2 - qh*dst_h2;
|
||||
int dw = dst_h;
|
||||
int dh = dst_w;
|
||||
|
||||
src += src_w - 1;
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
const uint8_t *s = src;
|
||||
#if LCD_WIDTH >= LCD_HEIGHT
|
||||
uint8_t * const dst_line_end = dst + dst_w;
|
||||
#else
|
||||
uint8_t * const dst_line_end = dst + dst_h;
|
||||
#endif
|
||||
while (1)
|
||||
{
|
||||
*dst++ = *s;
|
||||
|
||||
if (dst >= dst_line_end)
|
||||
{
|
||||
dw = dst_w;
|
||||
break;
|
||||
}
|
||||
|
||||
#if LCD_WIDTH >= LCD_HEIGHT
|
||||
s += qw;
|
||||
#else
|
||||
s += qw*stride;
|
||||
#endif
|
||||
dw += rw;
|
||||
|
||||
if (dw >= dst_w2)
|
||||
{
|
||||
dw -= dst_w2;
|
||||
#if LCD_WIDTH >= LCD_HEIGHT
|
||||
s++;
|
||||
#else
|
||||
s += stride;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (dst >= dst_end)
|
||||
break;
|
||||
#if LCD_WIDTH >= LCD_HEIGHT
|
||||
src += qh*stride;
|
||||
#else
|
||||
src -= qh;
|
||||
#endif
|
||||
dh += rh;
|
||||
|
||||
if (dh >= dst_h2)
|
||||
{
|
||||
dh -= dst_h2;
|
||||
#if LCD_WIDTH >= LCD_HEIGHT
|
||||
src += stride;
|
||||
#else
|
||||
src--;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool vo_draw_frame_thumb(uint8_t * const * buf, const struct vo_rect *rc)
|
||||
{
|
||||
void *mem;
|
||||
size_t bufsize = 0;
|
||||
uint8_t *yuv[3];
|
||||
struct vo_rect thumb_rc;
|
||||
int thumb_width, thumb_height;
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
int thumb_uv_width, thumb_uv_height;
|
||||
#endif
|
||||
|
||||
/* Obtain rectangle as clipped to the screen */
|
||||
vo_rect_set_ext(&thumb_rc, 0, 0, LCD_WIDTH, LCD_HEIGHT);
|
||||
if (!vo_rect_intersect(&thumb_rc, rc, &thumb_rc))
|
||||
return true;
|
||||
|
||||
if (buf == NULL)
|
||||
goto no_thumb_exit;
|
||||
|
||||
DEBUGF("thumb_rc: %d, %d, %d, %d\n", thumb_rc.l, thumb_rc.t,
|
||||
thumb_rc.r, thumb_rc.b);
|
||||
|
||||
thumb_width = rc->r - rc->l;
|
||||
thumb_height = rc->b - rc->t;
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
thumb_uv_width = thumb_width / 2;
|
||||
thumb_uv_height = thumb_height / 2;
|
||||
|
||||
DEBUGF("thumb: w: %d h: %d uvw: %d uvh: %d\n", thumb_width,
|
||||
thumb_height, thumb_uv_width, thumb_uv_height);
|
||||
#else
|
||||
DEBUGF("thumb: w: %d h: %d\n", thumb_width, thumb_height);
|
||||
#endif
|
||||
|
||||
/* Use remaining mpeg2 buffer as temp space */
|
||||
mem = mpeg2_get_buf(&bufsize);
|
||||
|
||||
if (bufsize < (size_t)(thumb_width*thumb_height)
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
+ 2u*(thumb_uv_width * thumb_uv_height)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
DEBUGF("thumb: insufficient buffer\n");
|
||||
goto no_thumb_exit;
|
||||
}
|
||||
|
||||
yuv[0] = mem;
|
||||
stretch_image_plane(buf[0], yuv[0], vo.image_width,
|
||||
vo.display_width, vo.display_height,
|
||||
thumb_width, thumb_height);
|
||||
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
yuv[1] = yuv[0] + thumb_width*thumb_height;
|
||||
yuv[2] = yuv[1] + thumb_uv_width*thumb_uv_height;
|
||||
|
||||
stretch_image_plane(buf[1], yuv[1], vo.image_width / 2,
|
||||
vo.display_width / 2, vo.display_height / 2,
|
||||
thumb_uv_width, thumb_uv_height);
|
||||
|
||||
stretch_image_plane(buf[2], yuv[2], vo.image_width / 2,
|
||||
vo.display_width / 2, vo.display_height / 2,
|
||||
thumb_uv_width, thumb_uv_height);
|
||||
#endif
|
||||
|
||||
#if LCD_WIDTH >= LCD_HEIGHT
|
||||
yuv_blit(yuv, 0, 0, thumb_width,
|
||||
thumb_rc.l, thumb_rc.t,
|
||||
thumb_rc.r - thumb_rc.l,
|
||||
thumb_rc.b - thumb_rc.t);
|
||||
#else
|
||||
yuv_blit(yuv, 0, 0, thumb_height,
|
||||
thumb_rc.t, thumb_rc.l,
|
||||
thumb_rc.b - thumb_rc.t,
|
||||
thumb_rc.r - thumb_rc.l);
|
||||
#endif /* LCD_WIDTH >= LCD_HEIGHT */
|
||||
|
||||
return true;
|
||||
|
||||
no_thumb_exit:
|
||||
vo_draw_black(&thumb_rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
void vo_setup(const mpeg2_sequence_t * sequence)
|
||||
{
|
||||
vo.image_width = sequence->width;
|
||||
vo.image_height = sequence->height;
|
||||
vo.display_width = sequence->display_width;
|
||||
vo.display_height = sequence->display_height;
|
||||
|
||||
DEBUGF("vo_setup - w:%d h:%d\n", vo.display_width, vo.display_height);
|
||||
|
||||
vo.image_chroma_x = vo.image_width / sequence->chroma_width;
|
||||
vo.image_chroma_y = vo.image_height / sequence->chroma_height;
|
||||
|
||||
if (sequence->display_width >= SCREEN_WIDTH)
|
||||
{
|
||||
vo.rc_vid.l = 0;
|
||||
vo.rc_vid.r = SCREEN_WIDTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
vo.rc_vid.l = (SCREEN_WIDTH - sequence->display_width) / 2;
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
vo.rc_vid.l &= ~1;
|
||||
#endif
|
||||
vo.rc_vid.r = vo.rc_vid.l + sequence->display_width;
|
||||
}
|
||||
|
||||
if (sequence->display_height >= SCREEN_HEIGHT)
|
||||
{
|
||||
vo.rc_vid.t = 0;
|
||||
vo.rc_vid.b = SCREEN_HEIGHT;
|
||||
}
|
||||
else
|
||||
{
|
||||
vo.rc_vid.t = (SCREEN_HEIGHT - sequence->display_height) / 2;
|
||||
#ifdef HAVE_LCD_COLOR
|
||||
vo.rc_vid.t &= ~1;
|
||||
#endif
|
||||
vo.rc_vid.b = vo.rc_vid.t + sequence->display_height;
|
||||
}
|
||||
|
||||
vo_set_clip_rect(&vo.rc_clip);
|
||||
}
|
||||
|
||||
void vo_dimensions(struct vo_ext *sz)
|
||||
{
|
||||
sz->w = vo.display_width;
|
||||
sz->h = vo.display_height;
|
||||
}
|
||||
|
||||
bool vo_init(void)
|
||||
{
|
||||
vo.flags = 0;
|
||||
vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
video_lock_init();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool vo_show(bool show)
|
||||
{
|
||||
bool vis = vo.flags & VO_VISIBLE;
|
||||
|
||||
if (show)
|
||||
vo.flags |= VO_VISIBLE;
|
||||
else
|
||||
vo.flags &= ~VO_VISIBLE;
|
||||
|
||||
return vis;
|
||||
}
|
||||
|
||||
bool vo_is_visible(void)
|
||||
{
|
||||
return vo.flags & VO_VISIBLE;
|
||||
}
|
||||
|
||||
void vo_cleanup(void)
|
||||
{
|
||||
vo.flags = 0;
|
||||
}
|
||||
|
||||
void vo_set_clip_rect(const struct vo_rect *rc)
|
||||
{
|
||||
struct vo_rect rc_out;
|
||||
|
||||
if (rc == NULL)
|
||||
vo_rect_set_ext(&vo.rc_clip, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||
else
|
||||
vo.rc_clip = *rc;
|
||||
|
||||
if (!vo_rect_intersect(&rc_out, &vo.rc_vid, &vo.rc_clip))
|
||||
vo.flags &= ~VO_NON_NULL_RECT;
|
||||
else
|
||||
vo.flags |= VO_NON_NULL_RECT;
|
||||
|
||||
vo.output_x = rc_out.l;
|
||||
vo.output_y = rc_out.t;
|
||||
vo.output_width = rc_out.r - rc_out.l;
|
||||
vo.output_height = rc_out.b - rc_out.t;
|
||||
}
|
||||
|
||||
bool vo_get_clip_rect(struct vo_rect *rc)
|
||||
{
|
||||
rc->l = vo.output_x;
|
||||
rc->t = vo.output_y;
|
||||
rc->r = rc->l + vo.output_width;
|
||||
rc->b = rc->t + vo.output_height;
|
||||
return (vo.flags & VO_NON_NULL_RECT) != 0;
|
||||
}
|
||||
|
||||
void vo_set_post_draw_callback(void (*cb)(void))
|
||||
{
|
||||
vo.post_draw_callback = cb;
|
||||
}
|
||||
|
||||
#if NUM_CORES > 1
|
||||
void vo_lock(void)
|
||||
{
|
||||
video_lock();
|
||||
}
|
||||
|
||||
void vo_unlock(void)
|
||||
{
|
||||
video_unlock();
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -71,10 +71,6 @@ wav,viewers/wavview,10
|
|||
wav,viewers/wav2wv,-
|
||||
wav,viewers/mp3_encoder,-
|
||||
wav,viewers/test_codec,-
|
||||
mpg,viewers/mpegplayer,4
|
||||
mpeg,viewers/mpegplayer,4
|
||||
mpv,viewers/mpegplayer,4
|
||||
m2v,viewers/mpegplayer,4
|
||||
iriver,viewers/iriver_flash,3
|
||||
tap,viewers/zxbox,12
|
||||
opx,viewers/open_plugins,-
|
||||
|
|
|
@ -189,7 +189,6 @@ Plugins
|
|||
:minesweeper: Antoine Cellerier
|
||||
:mosaique:
|
||||
:mp3_encoder:
|
||||
:mpegplayer: Michael Sevakis
|
||||
:nim:
|
||||
:oscilloscope: Jens Arnold
|
||||
:pacbox: Dave Chapman
|
||||
|
|
|
@ -7,16 +7,9 @@
|
|||
# $Id$
|
||||
#
|
||||
|
||||
# we need to build two different mad libraries
|
||||
# (one for codec, one for mpegplayer)
|
||||
# so a little trickery is necessary
|
||||
|
||||
MADFLAGS = $(CODECFLAGS) -I$(RBCODECLIB_DIR)/codecs/libmad
|
||||
MADFLAGS += -UDEBUG -DNDEBUG -DHAVE_LIMITS_H -DHAVE_ASSERT_H
|
||||
|
||||
# MPEGplayer
|
||||
MPEGMADFLAGS = $(MADFLAGS) -DMPEGPLAYER
|
||||
|
||||
# libmad
|
||||
MADLIB := $(CODECDIR)/libmad.a
|
||||
MADLIB_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/libmad/SOURCES)
|
||||
|
@ -27,26 +20,8 @@ $(MADLIB): $(MADLIB_OBJ)
|
|||
$(SILENT)$(shell rm -f $@)
|
||||
$(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
|
||||
|
||||
# libmad-mpeg
|
||||
MPEGMADLIB := $(CODECDIR)/libmad-mpeg.a
|
||||
MPEGMADLIB_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/libmad/SOURCES)
|
||||
MPEGMADLIB_OBJ := $(addsuffix .o,$(basename $(subst $(RBCODECLIB_DIR)/codecs/libmad,$(RBCODEC_BLD)/codecs/libmad-mpeg,$(MPEGMADLIB_SRC))))
|
||||
|
||||
$(MPEGMADLIB): $(MPEGMADLIB_OBJ)
|
||||
$(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
|
||||
|
||||
# pattern rules
|
||||
|
||||
$(CODECDIR)/libmad-mpeg/%.o : $(RBCODECLIB_DIR)/codecs/libmad/%.c
|
||||
$(SILENT)mkdir -p $(dir $@)
|
||||
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<)) \
|
||||
$(CC) $(MPEGMADFLAGS) -c $< -o $@
|
||||
|
||||
$(CODECDIR)/libmad-mpeg/%.o : $(RBCODECLIB_DIR)/codecs/libmad/%.S
|
||||
$(SILENT)mkdir -p $(dir $@)
|
||||
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<)) \
|
||||
$(CC) $(MPEGMADFLAGS) -c $< -o $@
|
||||
|
||||
$(CODECDIR)/libmad/%.o: $(RBCODECLIB_DIR)/codecs/libmad/%.c
|
||||
$(SILENT)mkdir -p $(dir $@)
|
||||
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<)) \
|
||||
|
|
|
@ -35,10 +35,9 @@
|
|||
#define ICODE_ATTR_MPA_SYNTH
|
||||
#define ICONST_ATTR_MPA_HUFFMAN
|
||||
#else
|
||||
/* Code performs slower in IRAM on PP502x and there is no space in
|
||||
mpegplayer on the PP5002. S3C2440 doesn't have any IRAM available for
|
||||
codecs */
|
||||
#if defined(CPU_PP502x) || (CONFIG_CPU == PP5002 && defined(MPEGPLAYER))
|
||||
/* Code performs slower in IRAM on PP502x
|
||||
S3C2440 doesn't have any IRAM available for codecs */
|
||||
#if defined(CPU_PP502x)
|
||||
#define ICODE_SECTION_MPA_ARM .text
|
||||
#define ICODE_ATTR_MPA_SYNTH
|
||||
#else
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
CODEC_HEADER
|
||||
|
||||
#if NUM_CORES > 1 && !defined(MPEGPLAYER)
|
||||
#if NUM_CORES > 1
|
||||
#define MPA_SYNTH_ON_COP
|
||||
#endif
|
||||
|
||||
|
|
|
@ -201,8 +201,6 @@ option from the \setting{Context Menu} (see \reference{ref:Contextmenu}).}
|
|||
\nopt{lowmem}{\input{plugins/midiplay.tex}}
|
||||
\nopt{lowmem}{\input{plugins/mikmod.tex}}
|
||||
|
||||
\nopt{lowmem}{\input{plugins/mpegplayer.tex}}
|
||||
|
||||
\input{plugins/mp3_encoder.tex}
|
||||
|
||||
\opt{iriverh300,iriverh100,SANSA_FUZE_PAD,SANSA_E200_PAD,IPOD_4G_PAD,IPOD_3G_PAD%
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
% $Id$ %
|
||||
\subsection{MPEG Player}
|
||||
The Mpeg Player is a video player plugin capable of playing back MPEG-1 and
|
||||
MPEG-2 video streams with MPEG audio multiplexed into \fname{.mpg} files.
|
||||
|
||||
To play a video file, you just select it in the Rockbox \setting{File Browser}.
|
||||
If your file does not have the \fname{.mpg} extension but is encoded in the
|
||||
supported format, you will need to use the \setting{Open With...} context menu
|
||||
option and choose \setting{mpegplayer}.
|
||||
|
||||
\begin{btnmap}
|
||||
\opt{GIGABEAT_S_PAD}{\ButtonSelect{} or \ButtonPlay}
|
||||
\opt{GIGABEAT_PAD}{\ButtonSelect{} or \ButtonA}
|
||||
\nopt{GIGABEAT_S_PAD,GIGABEAT_PAD}{\ActionWpsPlay}
|
||||
\opt{HAVEREMOTEKEYMAP}{& }
|
||||
& Pause / Resume\\
|
||||
\ActionWpsStop
|
||||
\opt{HAVEREMOTEKEYMAP}{& }
|
||||
& Stop\\
|
||||
\nopt{GIGABEAT_S_PAD,GIGABEAT_PAD}{\ActionWpsVolUp{} / \ActionWpsVolDown}
|
||||
\opt{GIGABEAT_S_PAD,GIGABEAT_PAD}{\ButtonLeft{} or \ButtonVolDown{} /
|
||||
\ButtonRight{} or \ButtonVolUp}
|
||||
\opt{HAVEREMOTEKEYMAP}{& }
|
||||
& Adjust volume up / down\\
|
||||
\nopt{GIGABEAT_S_PAD,GIGABEAT_PAD,SAMSUNG_YH92X_PAD,SAMSUNG_YH820_PAD}{%
|
||||
\ActionWpsSkipPrev{} / \ActionWpsSkipNext}
|
||||
\opt{GIGABEAT_S_PAD,GIGABEAT_PAD}{\ButtonUp{} / \ButtonDown}
|
||||
\opt{SAMSUNG_YH92X_PAD,SAMSUNG_YH820_PAD}{\ButtonLeft{} / \ButtonRight}
|
||||
\opt{HAVEREMOTEKEYMAP}{& }
|
||||
& Rewind / Fast Forward\\
|
||||
\opt{IRIVER_H100_PAD,IRIVER_H300_PAD}{\ButtonMode}
|
||||
\opt{IPOD_4G_PAD,IPOD_3G_PAD,GIGABEAT_PAD,GIGABEAT_S_PAD,MROBE100_PAD,PBELL_VIBE500_PAD}
|
||||
{\ButtonMenu}
|
||||
\opt{IAUDIO_X5_PAD}{\ButtonRec}
|
||||
\opt{IRIVER_H10_PAD}{\ButtonRew}
|
||||
\opt{SAMSUNG_YH92X_PAD,SAMSUNG_YH820_PAD}{\ButtonRew}
|
||||
\opt{SANSA_E200_PAD,SANSA_FUZE_PAD,SANSA_C200_PAD,SANSA_CLIP_PAD}{\ButtonSelect}
|
||||
\opt{HAVEREMOTEKEYMAP}{& }
|
||||
& Open the MPEG Player menu\\
|
||||
\end{btnmap}
|
||||
|
||||
When a video file is selected, the Start Menu will be displayed, unless it is
|
||||
disabled via the \setting{Resume Options} (see below). In the latter case the video
|
||||
will start playing immediately.
|
||||
|
||||
Start Menu
|
||||
|
||||
\begin{description}
|
||||
\item[Play from beginning] Resume information is discarded and the video plays
|
||||
from the start.
|
||||
\item[Resume at: mm:ss] Resume video playback at stored resume time mm:ss
|
||||
(start of the video if no resume time is found).
|
||||
\item[Set start time] A preview screen is presented consisting of a
|
||||
thumbnail preview and a progress bar where the user can select a start time
|
||||
by `seeking' through the video. The video playback is started by pressing
|
||||
the select button.
|
||||
\item[Settings] Open \setting{Settings} submenu -- see below.
|
||||
\item[Quit mpegplayer] Exit the plugin.
|
||||
\end{description}
|
||||
|
||||
Main Menu
|
||||
|
||||
\begin{description}
|
||||
\item[Settings] Open \setting{Settings} submenu -- see below.
|
||||
\item[Resume playback] Return to playback screen.
|
||||
\item[Quit mpegplayer] Exit the plugin.
|
||||
\end{description}
|
||||
|
||||
Settings Menu
|
||||
|
||||
\begin{description}
|
||||
\item[Display Options] Open \setting{Display Options} submenu -- see below.
|
||||
\item[Audio Options] Open \setting{Audio Options} submenu -- see below.
|
||||
\item[Resume Options] (default: Start menu) Enable/disable the start menu.
|
||||
\item[Play Mode] (default: Single) Set to \setting{All} to play multiple
|
||||
\fname{.mpg} files in the directory continuously.
|
||||
\item[Clear all resumes: x] Discard all x resume points.
|
||||
\end{description}
|
||||
|
||||
Display Options Menu
|
||||
|
||||
\begin{description}
|
||||
\item[Dithering] (default: off) Prevent banding effects in gradients by blending
|
||||
of colours. (only available on Sansa e200, Sansa c200 and Gigabeat F/X)
|
||||
\item[Display FPS] (default: off) This option displays (once a second -- if your
|
||||
video is full-screen this means it will get overwritten by the video and
|
||||
appear to flash once per second) the average number of frames decoded per
|
||||
second, the total number of frames skipped (see the Skip Frames option),
|
||||
the current time (in 100~Hz ticks) and the time the current frame is due to
|
||||
be displayed.
|
||||
\item[Limit FPS] (default: on) With this option disabled, mpegplayer will
|
||||
display the video as fast as it can. Useful for benchmarking.
|
||||
\item[Skip frames] (default: on) This option causes mpegplayer to attempt to
|
||||
maintain realtime playback by skipping the display of frames -- but these
|
||||
frames are still decoded. Disabling this option can cause loss of A/V sync.
|
||||
\opt{backlight_brightness}{
|
||||
\item[Backlight Brightness] (default: Use setting) Choose brightness to use
|
||||
during video playback. Set to \setting{Use setting} to use the Brightness
|
||||
setting.
|
||||
}
|
||||
\end{description}
|
||||
|
||||
Audio Options Menu
|
||||
|
||||
\begin{description}
|
||||
\item[Tone Controls] (default: force off) Use the bass and treble control
|
||||
settings or force them off.
|
||||
\item[Channel Modes] (default: force off) Use the channel configuration setting
|
||||
or force Stereo mode.
|
||||
\item[Crossfeed] (default: force off) Use the Crossfeed setting or force
|
||||
crossfeed off.
|
||||
\item[Equalizer] (default: force off) Use the Equalizer setting or force the
|
||||
equalizer off.
|
||||
\item[Dithering] (default: force off) Use the Dithering setting or force
|
||||
audio dithering off.
|
||||
\end{description}
|
||||
|
||||
See this page in the Rockbox wiki for information on how to encode your videos
|
||||
to the supported format. \wikilink{PluginMpegplayer}
|
Loading…
Reference in a new issue