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:
Solomon Peachy 2021-08-04 09:49:56 -04:00
parent 9ce5b2a2ed
commit d25d24812e
60 changed files with 5 additions and 21189 deletions

View file

@ -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

View file

@ -68,7 +68,6 @@ mikmod,viewers
minesweeper,games
mosaique,demos
mp3_encoder,apps
mpegplayer,viewers
multiboot_select,apps
nim,games
open_plugins,viewers

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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 */

View file

@ -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.

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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}

View file

@ -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

View file

@ -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
}
};

View file

@ -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); \
}

View file

@ -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)

View file

@ -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.

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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}
};

View file

@ -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 */

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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 $@

View file

@ -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 */

View file

@ -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);
}

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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,-

View file

@ -189,7 +189,6 @@ Plugins
:minesweeper: Antoine Cellerier
:mosaique:
:mp3_encoder:
:mpegplayer: Michael Sevakis
:nim:
:oscilloscope: Jens Arnold
:pacbox: Dave Chapman

View file

@ -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)/,,$<)) \

View file

@ -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

View file

@ -26,7 +26,7 @@
CODEC_HEADER
#if NUM_CORES > 1 && !defined(MPEGPLAYER)
#if NUM_CORES > 1
#define MPA_SYNTH_ON_COP
#endif

View file

@ -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%

View file

@ -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}