mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 10:11:08 +00:00
Add Interplay MVE format demuxer/decoder and muxer/encoder. Demuxer doesn't support seeking yet, but seems to work fi...
Original commit message from CVS: Patch by: Jens Granseuer <jensgr at gmx net> * configure.ac: * gst/mve/Makefile.am: * gst/mve/TODO: * gst/mve/gstmve.c: * gst/mve/gstmvedemux.c: * gst/mve/gstmvedemux.h: * gst/mve/gstmvemux.c: * gst/mve/gstmvemux.h: * gst/mve/mve.h: * gst/mve/mveaudiodec.c: * gst/mve/mveaudioenc.c: * gst/mve/mvevideodec16.c: * gst/mve/mvevideodec8.c: * gst/mve/mvevideoenc16.c: * gst/mve/mvevideoenc8.c: Add Interplay MVE format demuxer/decoder and muxer/encoder. Demuxer doesn't support seeking yet, but seems to work fine otherwise. Closes #348973.
This commit is contained in:
parent
abe3e58b1b
commit
5dbec4ecf4
16 changed files with 8237 additions and 1 deletions
23
ChangeLog
23
ChangeLog
|
@ -1,3 +1,26 @@
|
|||
2007-01-11 Tim-Philipp Müller <tim at centricular dot net>
|
||||
|
||||
Patch by: Jens Granseuer <jensgr at gmx net>
|
||||
|
||||
* configure.ac:
|
||||
* gst/mve/Makefile.am:
|
||||
* gst/mve/TODO:
|
||||
* gst/mve/gstmve.c:
|
||||
* gst/mve/gstmvedemux.c:
|
||||
* gst/mve/gstmvedemux.h:
|
||||
* gst/mve/gstmvemux.c:
|
||||
* gst/mve/gstmvemux.h:
|
||||
* gst/mve/mve.h:
|
||||
* gst/mve/mveaudiodec.c:
|
||||
* gst/mve/mveaudioenc.c:
|
||||
* gst/mve/mvevideodec16.c:
|
||||
* gst/mve/mvevideodec8.c:
|
||||
* gst/mve/mvevideoenc16.c:
|
||||
* gst/mve/mvevideoenc8.c:
|
||||
Add Interplay MVE format demuxer/decoder and muxer/encoder. Demuxer
|
||||
doesn't support seeking yet, but seems to work fine otherwise.
|
||||
Closes #348973.
|
||||
|
||||
2007-01-09 Tim-Philipp Müller <tim at centricular dot net>
|
||||
|
||||
* gst/real/Makefile.am:
|
||||
|
|
|
@ -86,6 +86,7 @@ GST_PLUGINS_ALL="\
|
|||
nuvdemux \
|
||||
modplug \
|
||||
multifile \
|
||||
mve \
|
||||
nsf \
|
||||
replaygain \
|
||||
spectrum \
|
||||
|
@ -924,10 +925,11 @@ gst/h264parse/Makefile
|
|||
gst/interleave/Makefile
|
||||
gst/librfb/Makefile
|
||||
gst/modplug/Makefile
|
||||
gst/nuvdemux/Makefile
|
||||
gst/modplug/libmodplug/Makefile
|
||||
gst/multifile/Makefile
|
||||
gst/mve/Makefile
|
||||
gst/nsf/Makefile
|
||||
gst/nuvdemux/Makefile
|
||||
gst/replaygain/Makefile
|
||||
gst/spectrum/Makefile
|
||||
gst/speed/Makefile
|
||||
|
|
20
gst/mve/Makefile.am
Normal file
20
gst/mve/Makefile.am
Normal file
|
@ -0,0 +1,20 @@
|
|||
plugin_LTLIBRARIES = libgstmve.la
|
||||
|
||||
libgstmve_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS)
|
||||
libgstmve_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS)
|
||||
libgstmve_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
libgstmve_la_SOURCES = \
|
||||
gstmve.c \
|
||||
gstmvemux.c \
|
||||
gstmvedemux.c \
|
||||
mveaudiodec.c \
|
||||
mvevideodec8.c \
|
||||
mvevideodec16.c \
|
||||
mveaudioenc.c \
|
||||
mvevideoenc8.c \
|
||||
mvevideoenc16.c
|
||||
|
||||
noinst_HEADERS = gstmvedemux.h gstmvemux.h mve.h
|
||||
|
||||
EXTRA_DIST = TODO
|
5
gst/mve/TODO
Normal file
5
gst/mve/TODO
Normal file
|
@ -0,0 +1,5 @@
|
|||
MVE TODO:
|
||||
- seeking support
|
||||
- split out decoders from demuxer into separate elements
|
||||
- split out encoders from muxer into separate elements
|
||||
|
46
gst/mve/gstmve.c
Normal file
46
gst/mve/gstmve.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* GStreamer plugin for Interplay MVE movie files
|
||||
*
|
||||
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* For more information about the Interplay MVE format, visit:
|
||||
* http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "gstmvedemux.h"
|
||||
#include "gstmvemux.h"
|
||||
|
||||
static gboolean
|
||||
mve_plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
|
||||
return gst_element_register (plugin, "mvedemux",
|
||||
GST_RANK_PRIMARY,
|
||||
GST_TYPE_MVE_DEMUX) &&
|
||||
gst_element_register (plugin, "mvemux", GST_RANK_NONE, GST_TYPE_MVE_MUX);
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"mve",
|
||||
"Interplay MVE movie format manipulation",
|
||||
mve_plugin_init,
|
||||
VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
|
1126
gst/mve/gstmvedemux.c
Normal file
1126
gst/mve/gstmvedemux.c
Normal file
File diff suppressed because it is too large
Load diff
104
gst/mve/gstmvedemux.h
Normal file
104
gst/mve/gstmvedemux.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* GStreamer demultiplexer plugin for Interplay MVE movie files
|
||||
*
|
||||
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_MVE_DEMUX_H__
|
||||
#define __GST_MVE_DEMUX_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstadapter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_MVE_DEMUX \
|
||||
(gst_mve_demux_get_type())
|
||||
#define GST_MVE_DEMUX(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MVE_DEMUX,GstMveDemux))
|
||||
#define GST_MVE_DEMUX_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MVE_DEMUX,GstMveDemuxClass))
|
||||
#define GST_IS_MVE_DEMUX(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MVE_DEMUX))
|
||||
#define GST_IS_MVE_DEMUX_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MVE_DEMUX))
|
||||
|
||||
typedef struct _GstMveDemux GstMveDemux;
|
||||
typedef struct _GstMveDemuxClass GstMveDemuxClass;
|
||||
typedef struct _GstMveDemuxStream GstMveDemuxStream;
|
||||
|
||||
struct _GstMveDemux
|
||||
{
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
|
||||
GstMveDemuxStream *video_stream;
|
||||
GstMveDemuxStream *audio_stream;
|
||||
|
||||
gint state;
|
||||
|
||||
/* time per frame (1/framerate) */
|
||||
GstClockTime frame_duration;
|
||||
|
||||
/* push based variables */
|
||||
guint16 needed_bytes;
|
||||
GstAdapter *adapter;
|
||||
|
||||
/* size of current chunk */
|
||||
guint32 chunk_size;
|
||||
/* offset in current chunk */
|
||||
guint32 chunk_offset;
|
||||
};
|
||||
|
||||
struct _GstMveDemuxClass
|
||||
{
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
struct _GstMveDemuxStream {
|
||||
/* shared properties */
|
||||
GstCaps *caps;
|
||||
GstPad *pad;
|
||||
GstClockTime last_ts;
|
||||
gint64 offset;
|
||||
|
||||
/* video properties */
|
||||
guint16 width;
|
||||
guint16 height;
|
||||
guint8 bpp; /* bytes per pixel */
|
||||
guint8 *code_map;
|
||||
gboolean code_map_avail;
|
||||
guint8 *back_buf1;
|
||||
guint8 *back_buf2;
|
||||
guint32 max_block_offset;
|
||||
GstBuffer *palette;
|
||||
GstBuffer *buffer;
|
||||
|
||||
/* audio properties */
|
||||
guint16 sample_rate;
|
||||
guint16 n_channels;
|
||||
guint16 sample_size;
|
||||
gboolean compression;
|
||||
};
|
||||
|
||||
GType gst_mve_demux_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_MVE_DEMUX_H__ */
|
1493
gst/mve/gstmvemux.c
Normal file
1493
gst/mve/gstmvemux.c
Normal file
File diff suppressed because it is too large
Load diff
120
gst/mve/gstmvemux.h
Normal file
120
gst/mve/gstmvemux.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Interplay MVE muxer plugin for GStreamer
|
||||
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_MVE_MUX_H__
|
||||
#define __GST_MVE_MUX_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_MVE_MUX \
|
||||
(gst_mve_mux_get_type())
|
||||
#define GST_MVE_MUX(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MVE_MUX,GstMveMux))
|
||||
#define GST_MVE_MUX_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MVE_MUX,GstMveMux))
|
||||
#define GST_IS_MVE_MUX(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MVE_MUX))
|
||||
#define GST_IS_MVE_MUX_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MVE_MUX))
|
||||
|
||||
|
||||
typedef struct _GstMveMux GstMveMux;
|
||||
typedef struct _GstMveMuxClass GstMveMuxClass;
|
||||
|
||||
struct _GstMveMux {
|
||||
GstElement element;
|
||||
GMutex *lock;
|
||||
|
||||
/* pads */
|
||||
GstPad *source;
|
||||
GstPad *videosink;
|
||||
GstPad *audiosink;
|
||||
|
||||
gboolean audio_pad_connected;
|
||||
gboolean audio_pad_eos;
|
||||
gboolean video_pad_connected;
|
||||
gboolean video_pad_eos;
|
||||
|
||||
guint64 stream_offset;
|
||||
/* audio stream time, really */
|
||||
GstClockTime stream_time;
|
||||
guint timer;
|
||||
gint state;
|
||||
|
||||
/* ticks per frame */
|
||||
GstClockTime frame_duration;
|
||||
|
||||
/* video stream properties */
|
||||
guint16 width, height;
|
||||
guint16 screen_width, screen_height;
|
||||
/* bits per pixel */
|
||||
guint8 bpp;
|
||||
/* previous frames */
|
||||
GstBuffer *last_frame;
|
||||
GstBuffer *second_last_frame;
|
||||
/* number of encoded frames */
|
||||
guint16 video_frames;
|
||||
/* palette handling */
|
||||
gboolean pal_changed;
|
||||
guint16 pal_first_color;
|
||||
guint16 pal_colors;
|
||||
/* whether to use expensive opcodes */
|
||||
gboolean quick_encoding;
|
||||
|
||||
/* audio stream properties */
|
||||
/* bits per sample */
|
||||
guint8 bps;
|
||||
guint32 rate;
|
||||
guint8 channels;
|
||||
gboolean compression;
|
||||
/* current audio stream time */
|
||||
GstClockTime next_ts;
|
||||
/* maximum audio time we know about */
|
||||
GstClockTime max_ts;
|
||||
/* sample bytes per frame */
|
||||
guint16 spf;
|
||||
/* number of frames to use for audio lead-in */
|
||||
guint16 lead_frames;
|
||||
/* number of encoded frames */
|
||||
guint16 audio_frames;
|
||||
|
||||
/* current chunk */
|
||||
guint8 *chunk_code_map;
|
||||
GByteArray *chunk_video;
|
||||
GByteArray *chunk_audio;
|
||||
gboolean chunk_has_palette;
|
||||
gboolean chunk_has_audio;
|
||||
|
||||
/* buffers for incoming data */
|
||||
GQueue *audio_buffer;
|
||||
GQueue *video_buffer;
|
||||
};
|
||||
|
||||
struct _GstMveMuxClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_mve_mux_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_MVE_MUX_H__ */
|
62
gst/mve/mve.h
Normal file
62
gst/mve/mve.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Interplay MVE movie definitions
|
||||
*
|
||||
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __MVE_H__
|
||||
#define __MVE_H__
|
||||
|
||||
#define MVE_PREAMBLE "Interplay MVE File\032\000\032\000\000\001\063\021"
|
||||
#define MVE_PREAMBLE_SIZE 26
|
||||
|
||||
#define MVE_PALETTE_COUNT 256
|
||||
|
||||
/* MVE chunk types */
|
||||
#define MVE_CHUNK_INIT_AUDIO 0x0000
|
||||
#define MVE_CHUNK_AUDIO_ONLY 0x0001
|
||||
#define MVE_CHUNK_INIT_VIDEO 0x0002
|
||||
#define MVE_CHUNK_VIDEO 0x0003
|
||||
#define MVE_CHUNK_SHUTDOWN 0x0004
|
||||
#define MVE_CHUNK_END 0x0005
|
||||
|
||||
/* MVE segment opcodes */
|
||||
#define MVE_OC_END_OF_STREAM 0x00
|
||||
#define MVE_OC_END_OF_CHUNK 0x01
|
||||
#define MVE_OC_CREATE_TIMER 0x02
|
||||
#define MVE_OC_AUDIO_BUFFERS 0x03
|
||||
#define MVE_OC_PLAY_AUDIO 0x04
|
||||
#define MVE_OC_VIDEO_BUFFERS 0x05
|
||||
#define MVE_OC_PLAY_VIDEO 0x07
|
||||
#define MVE_OC_AUDIO_DATA 0x08
|
||||
#define MVE_OC_AUDIO_SILENCE 0x09
|
||||
#define MVE_OC_VIDEO_MODE 0x0A
|
||||
#define MVE_OC_PALETTE 0x0C
|
||||
#define MVE_OC_PALETTE_COMPRESSED 0x0D
|
||||
#define MVE_OC_CODE_MAP 0x0F
|
||||
#define MVE_OC_VIDEO_DATA 0x11
|
||||
|
||||
/* audio flags */
|
||||
#define MVE_AUDIO_STEREO 0x0001
|
||||
#define MVE_AUDIO_16BIT 0x0002
|
||||
#define MVE_AUDIO_COMPRESSED 0x0004
|
||||
|
||||
/* video flags */
|
||||
#define MVE_VIDEO_DELTA_FRAME 0x0001
|
||||
|
||||
#endif /* __MVE_H__ */
|
82
gst/mve/mveaudiodec.c
Normal file
82
gst/mve/mveaudiodec.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2003 The ffmpeg Project, Mike Melanson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Interplay compressed audio codec by Mike Melanson (melanson@pcisys.net)
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
static const short delta_table[256] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 47, 51, 56, 61,
|
||||
66, 72, 79, 86, 94, 102, 112, 122, 133, 145, 158, 173, 189, 206, 225, 245,
|
||||
267, 292, 318, 348, 379, 414, 452, 493, 538, 587, 640, 699, 763, 832, 908,
|
||||
991,
|
||||
1081, 1180, 1288, 1405, 1534, 1673, 1826, 1993, 2175, 2373, 2590, 2826, 3084,
|
||||
3365, 3672, 4008,
|
||||
4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, 8794, 9597, 10472, 11428,
|
||||
12471, 13609, 14851, 16206,
|
||||
17685, 19298, 21060, 22981, 25078, 27367, 29864, 32589, -29973, -26728,
|
||||
-23186, -19322, -15105, -10503, -5481, -1,
|
||||
1, 1, 5481, 10503, 15105, 19322, 23186, 26728, 29973, -32589, -29864, -27367,
|
||||
-25078, -22981, -21060, -19298,
|
||||
-17685, -16206, -14851, -13609, -12471, -11428, -10472, -9597, -8794, -8059,
|
||||
-7385, -6767, -6202, -5683, -5208, -4772,
|
||||
-4373, -4008, -3672, -3365, -3084, -2826, -2590, -2373, -2175, -1993, -1826,
|
||||
-1673, -1534, -1405, -1288, -1180,
|
||||
-1081, -991, -908, -832, -763, -699, -640, -587, -538, -493, -452, -414, -379,
|
||||
-348, -318, -292,
|
||||
-267, -245, -225, -206, -189, -173, -158, -145, -133, -122, -112, -102, -94,
|
||||
-86, -79, -72,
|
||||
-66, -61, -56, -51, -47, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34,
|
||||
-33,
|
||||
-32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18,
|
||||
-17,
|
||||
-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1
|
||||
};
|
||||
|
||||
void
|
||||
ipaudio_uncompress (short *buffer, unsigned short buf_len,
|
||||
const unsigned char *data, unsigned char channels)
|
||||
{
|
||||
int i, out = 0;
|
||||
int predictor[2];
|
||||
int channel_number = 0;
|
||||
|
||||
for (i = 0; i < channels; ++i) {
|
||||
predictor[i] = GST_READ_UINT16_LE (data);
|
||||
data += 2;
|
||||
if (predictor[i] & 0x8000)
|
||||
predictor[i] -= 0x10000;
|
||||
buffer[out++] = predictor[i];
|
||||
}
|
||||
|
||||
/* we count in 16-bit ints, so adjust the buffer size */
|
||||
buf_len /= 2;
|
||||
while (out < buf_len) {
|
||||
predictor[channel_number] += delta_table[*data++];
|
||||
if (predictor[channel_number] < -32768)
|
||||
predictor[channel_number] = -32768;
|
||||
else if (predictor[channel_number] > 32767)
|
||||
predictor[channel_number] = 32767;
|
||||
buffer[out++] = predictor[channel_number];
|
||||
|
||||
/* toggle channel */
|
||||
channel_number ^= channels - 1;
|
||||
}
|
||||
}
|
120
gst/mve/mveaudioenc.c
Normal file
120
gst/mve/mveaudioenc.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Interplay MVE audio compressor
|
||||
* Copyright (C) 2003, 2004 Alexander Belyakov <abel@krasu.ru>
|
||||
* Copyright (C) 2006 Jens Granseuer <jensgr@gmx.net>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
static const gint32 dec_table[256] =
|
||||
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37,
|
||||
38, 39, 40, 41, 42, 43, 47, 51, 56, 61,
66, 72, 79, 86, 94, 102, 112,
|
||||
122, 133, 145, 158, 173, 189, 206, 225, 245,
267, 292, 318, 348, 379,
|
||||
414, 452, 493, 538, 587, 640, 699, 763, 832, 908, 991,
1081, 1180, 1288,
|
||||
1405, 1534, 1673, 1826, 1993, 2175, 2373, 2590, 2826, 3084, 3365, 3672,
|
||||
4008,
4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, 8794, 9597, 10472,
|
||||
11428, 12471, 13609, 14851, 16206,
17685, 19298, 21060, 22981, 25078,
|
||||
27367, 29864, 32589, 35563, 38808, 42350, 46214, 50431, 55033, 60055,
|
||||
65535,
1, -65535, -60055, -55033, -50431, -46214, -42350, -38808, -35563,
|
||||
-32589, -29864, -27367, -25078, -22981, -21060, -19298,
-17685, -16206,
|
||||
-14851, -13609, -12471, -11428, -10472, -9597, -8794, -8059, -7385, -6767,
|
||||
-6202, -5683, -5208, -4772,
-4373, -4008, -3672, -3365, -3084, -2826,
|
||||
-2590, -2373, -2175, -1993, -1826, -1673, -1534, -1405, -1288, -1180,
|
||||
-1081, -991, -908, -832, -763, -699, -640, -587, -538, -493, -452, -414,
|
||||
-379, -348, -318, -292,
-267, -245, -225, -206, -189, -173, -158, -145,
|
||||
-133, -122, -112, -102, -94, -86, -79, -72,
-66, -61, -56, -51, -47, -43,
|
||||
-42, -41, -40, -39, -38, -37, -36, -35, -34, -33,
-32, -31, -30, -29,
|
||||
-28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17,
-16, -15,
|
||||
-14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1
|
||||
};
|
||||
|
||||
|
||||
/* This value could be non-optimal. Without knowledge of the value
|
||||
distribution in the real signal, the actual optimum cannot be evaluated.
|
||||
Should be somewhere between 11.458 and 11.542. */
|
||||
static const gdouble DPCM_SCALE = 11.5131;
|
||||
static gint8
|
||||
mve_enc_delta (guint n)
|
||||
{
|
||||
if (n < 44)
|
||||
return n;
|
||||
return floor (DPCM_SCALE * log (n));
|
||||
}
|
||||
|
||||
gint
|
||||
mve_compress_audio (guint8 * dest, const guint8 * src, guint16 len,
|
||||
guint8 channels)
|
||||
{
|
||||
gint16 prev[2], s;
|
||||
gint delta, real_res;
|
||||
gint cur_chan;
|
||||
guint8 v;
|
||||
|
||||
for (cur_chan = 0; cur_chan < channels; ++cur_chan) {
|
||||
prev[cur_chan] = GST_READ_UINT16_LE (src);
|
||||
GST_WRITE_UINT16_LE (dest, prev[cur_chan]);
|
||||
src += 2;
|
||||
dest += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
cur_chan = 0;
|
||||
while (len > 0) {
|
||||
s = GST_READ_UINT16_LE (src);
|
||||
src += 2;
|
||||
|
||||
delta = s - prev[cur_chan];
|
||||
if (delta >= 0)
|
||||
v = mve_enc_delta (delta);
|
||||
|
||||
else
|
||||
v = 256 - mve_enc_delta (-delta);
|
||||
real_res = dec_table[v] + prev[cur_chan];
|
||||
if (real_res < -32768 || real_res > 32767) {
|
||||
|
||||
/* correct overflow */
|
||||
/* GST_DEBUG ("co:%d + %d = %d -> new v:%d, dec_table:%d will be %d",
|
||||
prev[cur_chan], dec_table[v], real_res,
|
||||
v, dec_table[v], prev[cur_chan]+dec_table[v]); */
|
||||
if (s > 0) {
|
||||
if (real_res > 32767)
|
||||
--v;
|
||||
} else {
|
||||
if (real_res < -32768)
|
||||
++v;
|
||||
}
|
||||
|
||||
real_res = dec_table[v] + prev[cur_chan];
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (abs (real_res - s) > 32767)) {
|
||||
GST_ERROR ("sign loss left unfixed in audio stream, deviation:%ld",
|
||||
real_res - s);
|
||||
return -1;
|
||||
}
|
||||
*dest++ = v;
|
||||
--len;
|
||||
/* use previous output instead of input. That way output will not go too far from input. */
|
||||
prev[cur_chan] += dec_table[v];
|
||||
cur_chan = channels - 1 - cur_chan;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
849
gst/mve/mvevideodec16.c
Normal file
849
gst/mve/mvevideodec16.c
Normal file
|
@ -0,0 +1,849 @@
|
|||
/*
|
||||
* Interplay MVE Video Decoder (16 bit)
|
||||
* Copyright (C) 2003 the ffmpeg project, Mike Melanson
|
||||
* (C) 2006 Jens Granseuer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* For more information about the Interplay MVE format, visit:
|
||||
* http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
|
||||
*/
|
||||
|
||||
#include "gstmvedemux.h"
|
||||
#include <string.h>
|
||||
|
||||
#define PIXEL(s) GST_READ_UINT16_LE (s)
|
||||
|
||||
#define CHECK_STREAM(l, n) \
|
||||
do { \
|
||||
if (G_UNLIKELY (*(l) < (n))) { \
|
||||
GST_ERROR ("wanted to read %d bytes from stream, %d available", (n), *(l)); \
|
||||
return -1; \
|
||||
} \
|
||||
*(l) -= (n); \
|
||||
} while (0)
|
||||
|
||||
/* copy an 8x8 block from the stream to the frame buffer */
|
||||
static int
|
||||
ipvideo_copy_block (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned short *src, int offset)
|
||||
{
|
||||
int i;
|
||||
int frame_offset;
|
||||
|
||||
frame_offset = frame - (unsigned short *) s->back_buf1 + offset;
|
||||
|
||||
if (G_UNLIKELY (frame_offset < 0)) {
|
||||
GST_ERROR ("frame offset < 0 (%ld)", frame_offset);
|
||||
return -1;
|
||||
} else if (G_UNLIKELY (frame_offset > s->max_block_offset)) {
|
||||
GST_ERROR ("frame offset above limit (%ld > %ld)",
|
||||
frame_offset, s->max_block_offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
memcpy (frame, src, 16);
|
||||
frame += s->width;
|
||||
src += s->width;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x2 (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
unsigned char B;
|
||||
int x, y;
|
||||
int offset;
|
||||
|
||||
/* copy block from 2 frames ago using a motion vector */
|
||||
CHECK_STREAM (len, 1);
|
||||
B = *(*data)++;
|
||||
|
||||
if (B < 56) {
|
||||
x = 8 + (B % 7);
|
||||
y = B / 7;
|
||||
} else {
|
||||
x = -14 + ((B - 56) % 29);
|
||||
y = 8 + ((B - 56) / 29);
|
||||
}
|
||||
offset = y * s->width + x;
|
||||
|
||||
return ipvideo_copy_block (s, frame, frame + offset, offset);
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x3 (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
unsigned char B;
|
||||
int x, y;
|
||||
int offset;
|
||||
|
||||
/* copy 8x8 block from current frame from an up/left block */
|
||||
CHECK_STREAM (len, 1);
|
||||
B = *(*data)++;
|
||||
|
||||
if (B < 56) {
|
||||
x = -(8 + (B % 7));
|
||||
y = -(B / 7);
|
||||
} else {
|
||||
x = -(-14 + ((B - 56) % 29));
|
||||
y = -(8 + ((B - 56) / 29));
|
||||
}
|
||||
offset = y * s->width + x;
|
||||
|
||||
return ipvideo_copy_block (s, frame, frame + offset, offset);
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x4 (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char B;
|
||||
int offset;
|
||||
|
||||
/* copy a block from the previous frame */
|
||||
CHECK_STREAM (len, 1);
|
||||
B = *(*data)++;
|
||||
x = -8 + (B & 0x0F);
|
||||
y = -8 + (B >> 4);
|
||||
offset = y * s->width + x;
|
||||
|
||||
return ipvideo_copy_block (s, frame, frame +
|
||||
((unsigned short *) s->back_buf2 - (unsigned short *) s->back_buf1) +
|
||||
offset, offset);
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x5 (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
signed char x, y;
|
||||
int offset;
|
||||
|
||||
/* copy a block from the previous frame using an expanded range */
|
||||
CHECK_STREAM (len, 2);
|
||||
x = (signed char) *(*data)++;
|
||||
y = (signed char) *(*data)++;
|
||||
offset = y * s->width + x;
|
||||
|
||||
return ipvideo_copy_block (s, frame, frame +
|
||||
((unsigned short *) s->back_buf2 - (unsigned short *) s->back_buf1) +
|
||||
offset, offset);
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x7 (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned short P0, P1;
|
||||
unsigned int flags;
|
||||
int bitmask;
|
||||
|
||||
/* 2-color encoding */
|
||||
CHECK_STREAM (len, 4 + 2);
|
||||
P0 = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P1 = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
|
||||
if (!(P0 & 0x8000)) {
|
||||
|
||||
/* need 8 more bytes from the stream */
|
||||
CHECK_STREAM (len, 8 - 2);
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
flags = *(*data)++;
|
||||
for (x = 0x01; x <= 0x80; x <<= 1) {
|
||||
if (flags & x)
|
||||
*frame++ = P1;
|
||||
else
|
||||
*frame++ = P0;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
P0 &= ~0x8000;
|
||||
|
||||
/* need 2 more bytes from the stream */
|
||||
|
||||
flags = ((*data)[1] << 8) | (*data)[0];
|
||||
(*data) += 2;
|
||||
bitmask = 0x0001;
|
||||
for (y = 0; y < 8; y += 2) {
|
||||
for (x = 0; x < 8; x += 2, bitmask <<= 1) {
|
||||
if (flags & bitmask) {
|
||||
*(frame + x) = P1;
|
||||
*(frame + x + 1) = P1;
|
||||
*(frame + s->width + x) = P1;
|
||||
*(frame + s->width + x + 1) = P1;
|
||||
} else {
|
||||
*(frame + x) = P0;
|
||||
*(frame + x + 1) = P0;
|
||||
*(frame + s->width + x) = P0;
|
||||
*(frame + s->width + x + 1) = P0;
|
||||
}
|
||||
}
|
||||
frame += s->width * 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x8 (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned short P[8];
|
||||
unsigned char B[8];
|
||||
unsigned int flags = 0;
|
||||
unsigned int bitmask = 0;
|
||||
unsigned short P0 = 0, P1 = 0;
|
||||
int lower_half = 0;
|
||||
|
||||
/* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
|
||||
* either top and bottom or left and right halves */
|
||||
CHECK_STREAM (len, 6 + 10);
|
||||
|
||||
P[0] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[1] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
B[0] = *(*data)++;
|
||||
B[1] = *(*data)++;
|
||||
|
||||
if (!(P[0] & 0x8000)) {
|
||||
|
||||
/* need 18 more bytes */
|
||||
CHECK_STREAM (len, 18 - 10);
|
||||
|
||||
P[2] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[3] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
B[2] = *(*data)++;
|
||||
B[3] = *(*data)++;
|
||||
P[4] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[5] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
B[4] = *(*data)++;
|
||||
B[5] = *(*data)++;
|
||||
P[6] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[7] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
B[6] = *(*data)++;
|
||||
B[7] = *(*data)++;
|
||||
|
||||
flags =
|
||||
((B[0] & 0xF0) << 4) | ((B[4] & 0xF0) << 8) |
|
||||
((B[0] & 0x0F)) | ((B[4] & 0x0F) << 4) |
|
||||
((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
|
||||
((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
|
||||
bitmask = 0x00000001;
|
||||
lower_half = 0; /* still on top half */
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
/* time to reload flags? */
|
||||
if (y == 4) {
|
||||
flags =
|
||||
((B[2] & 0xF0) << 4) | ((B[6] & 0xF0) << 8) |
|
||||
((B[2] & 0x0F)) | ((B[6] & 0x0F) << 4) |
|
||||
((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
|
||||
((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
|
||||
bitmask = 0x00000001;
|
||||
lower_half = 2;
|
||||
}
|
||||
|
||||
/* get the pixel values ready for this quadrant */
|
||||
P0 = P[lower_half + 0];
|
||||
P1 = P[lower_half + 1];
|
||||
|
||||
for (x = 0; x < 8; ++x, bitmask <<= 1) {
|
||||
if (x == 4) {
|
||||
P0 = P[lower_half + 4];
|
||||
P1 = P[lower_half + 5];
|
||||
}
|
||||
|
||||
if (flags & bitmask)
|
||||
*frame++ = P1;
|
||||
else
|
||||
*frame++ = P0;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
P[0] &= ~0x8000;
|
||||
|
||||
/* need 10 more bytes */
|
||||
B[2] = *(*data)++;
|
||||
B[3] = *(*data)++;
|
||||
P[2] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[3] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
B[4] = *(*data)++;
|
||||
B[5] = *(*data)++;
|
||||
B[6] = *(*data)++;
|
||||
B[7] = *(*data)++;
|
||||
|
||||
if (!(P[2] & 0x8000)) {
|
||||
/* vertical split; left & right halves are 2-color encoded */
|
||||
|
||||
flags =
|
||||
((B[0] & 0xF0) << 4) | ((B[4] & 0xF0) << 8) |
|
||||
((B[0] & 0x0F)) | ((B[4] & 0x0F) << 4) |
|
||||
((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
|
||||
((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
|
||||
bitmask = 0x00000001;
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
/* time to reload flags? */
|
||||
if (y == 4) {
|
||||
flags =
|
||||
((B[2] & 0xF0) << 4) | ((B[6] & 0xF0) << 8) |
|
||||
((B[2] & 0x0F)) | ((B[6] & 0x0F) << 4) |
|
||||
((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
|
||||
((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
|
||||
bitmask = 0x00000001;
|
||||
}
|
||||
|
||||
/* get the pixel values ready for this half */
|
||||
P0 = P[0];
|
||||
P1 = P[1];
|
||||
|
||||
for (x = 0; x < 8; ++x, bitmask <<= 1) {
|
||||
if (x == 4) {
|
||||
P0 = P[2];
|
||||
P1 = P[3];
|
||||
}
|
||||
|
||||
if (flags & bitmask)
|
||||
*frame++ = P1;
|
||||
else
|
||||
*frame++ = P0;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* horizontal split; top & bottom halves are 2-color encoded */
|
||||
|
||||
P0 = P[0];
|
||||
P1 = P[1];
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
flags = B[y];
|
||||
if (y == 4) {
|
||||
P0 = P[2] & ~0x8000;
|
||||
P1 = P[3];
|
||||
}
|
||||
|
||||
for (bitmask = 0x01; bitmask <= 0x80; bitmask <<= 1) {
|
||||
|
||||
if (flags & bitmask)
|
||||
*frame++ = P1;
|
||||
else
|
||||
*frame++ = P0;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x9 (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned short P[4];
|
||||
unsigned char B[4];
|
||||
unsigned int flags = 0;
|
||||
int shifter = 0;
|
||||
unsigned short pix;
|
||||
|
||||
/* 4-color encoding */
|
||||
CHECK_STREAM (len, 8 + 4);
|
||||
|
||||
P[0] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[1] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[2] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[3] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
|
||||
if (!(P[0] & 0x8000) && !(P[2] & 0x8000)) {
|
||||
|
||||
/* 1 of 4 colors for each pixel, need 16 more bytes */
|
||||
CHECK_STREAM (len, 16 - 4);
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
/* get the next set of 8 2-bit flags */
|
||||
flags = ((*data)[1] << 8) | (*data)[0];
|
||||
(*data) += 2;
|
||||
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
|
||||
*frame++ = P[(flags >> shifter) & 0x03];
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else if (!(P[0] & 0x8000) && (P[2] & 0x8000)) {
|
||||
P[2] &= ~0x8000;
|
||||
|
||||
/* 1 of 4 colors for each 2x2 block, need 4 more bytes */
|
||||
|
||||
B[0] = *(*data)++;
|
||||
B[1] = *(*data)++;
|
||||
B[2] = *(*data)++;
|
||||
B[3] = *(*data)++;
|
||||
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
|
||||
shifter = 0;
|
||||
|
||||
for (y = 0; y < 8; y += 2) {
|
||||
for (x = 0; x < 8; x += 2, shifter += 2) {
|
||||
pix = P[(flags >> shifter) & 0x03];
|
||||
*(frame + x) = pix;
|
||||
*(frame + x + 1) = pix;
|
||||
*(frame + s->width + x) = pix;
|
||||
*(frame + s->width + x + 1) = pix;
|
||||
}
|
||||
frame += s->width * 2;
|
||||
}
|
||||
|
||||
} else if ((P[0] & 0x8000) && !(P[2] & 0x8000)) {
|
||||
P[0] &= ~0x8000;
|
||||
|
||||
/* 1 of 4 colors for each 2x1 block, need 8 more bytes */
|
||||
|
||||
CHECK_STREAM (len, 8 - 4);
|
||||
for (y = 0; y < 8; ++y) {
|
||||
/* time to reload flags? */
|
||||
if ((y == 0) || (y == 4)) {
|
||||
B[0] = *(*data)++;
|
||||
B[1] = *(*data)++;
|
||||
B[2] = *(*data)++;
|
||||
B[3] = *(*data)++;
|
||||
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
|
||||
shifter = 0;
|
||||
}
|
||||
for (x = 0; x < 8; x += 2, shifter += 2) {
|
||||
pix = P[(flags >> shifter) & 0x03];
|
||||
*(frame + x) = pix;
|
||||
*(frame + x + 1) = pix;
|
||||
}
|
||||
frame += s->width;
|
||||
}
|
||||
|
||||
} else {
|
||||
P[0] &= ~0x8000;
|
||||
P[2] &= ~0x8000;
|
||||
|
||||
/* 1 of 4 colors for each 1x2 block, need 8 more bytes */
|
||||
CHECK_STREAM (len, 8 - 4);
|
||||
|
||||
for (y = 0; y < 8; y += 2) {
|
||||
/* time to reload flags? */
|
||||
if ((y == 0) || (y == 4)) {
|
||||
B[0] = *(*data)++;
|
||||
B[1] = *(*data)++;
|
||||
B[2] = *(*data)++;
|
||||
B[3] = *(*data)++;
|
||||
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
|
||||
shifter = 0;
|
||||
}
|
||||
for (x = 0; x < 8; ++x, shifter += 2) {
|
||||
pix = P[(flags >> shifter) & 0x03];
|
||||
*(frame + x) = pix;
|
||||
*(frame + s->width + x) = pix;
|
||||
}
|
||||
frame += s->width * 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xa (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned short P[16];
|
||||
unsigned char B[16];
|
||||
int flags = 0;
|
||||
int shifter = 0;
|
||||
int index;
|
||||
int split;
|
||||
int lower_half;
|
||||
|
||||
/* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
|
||||
* either top and bottom or left and right halves */
|
||||
CHECK_STREAM (len, 8 + 24);
|
||||
|
||||
P[0] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[1] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[2] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[3] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
|
||||
if (!(P[0] & 0x8000)) {
|
||||
|
||||
/* 4-color encoding for each quadrant; need 40 more bytes */
|
||||
CHECK_STREAM (len, 40 - 24);
|
||||
|
||||
B[0] = *(*data)++;
|
||||
B[1] = *(*data)++;
|
||||
B[2] = *(*data)++;
|
||||
B[3] = *(*data)++;
|
||||
for (y = 4; y < 16; y += 4) {
|
||||
for (x = y; x < y + 4; ++x) {
|
||||
P[x] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
}
|
||||
for (x = y; x < y + 4; ++x)
|
||||
B[x] = *(*data)++;
|
||||
}
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
lower_half = (y >= 4) ? 4 : 0;
|
||||
flags = (B[y + 8] << 8) | B[y];
|
||||
|
||||
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
|
||||
split = (x >= 4) ? 8 : 0;
|
||||
index = split + lower_half + ((flags >> shifter) & 0x03);
|
||||
*frame++ = P[index];
|
||||
}
|
||||
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
P[0] &= ~0x8000;
|
||||
|
||||
/* 4-color encoding for either left and right or top and bottom
|
||||
* halves; need 24 more bytes */
|
||||
|
||||
memcpy (&B[0], *data, 8);
|
||||
(*data) += 8;
|
||||
P[4] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[5] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[6] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[7] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
memcpy (&B[8], *data, 8);
|
||||
(*data) += 8;
|
||||
|
||||
if (!(P[4] & 0x8000)) {
|
||||
|
||||
/* block is divided into left and right halves */
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
flags = (B[y + 8] << 8) | B[y];
|
||||
split = 0;
|
||||
|
||||
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
|
||||
if (x == 4)
|
||||
split = 4;
|
||||
*frame++ = P[split + ((flags >> shifter) & 0x03)];
|
||||
}
|
||||
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
P[4] &= ~0x8000;
|
||||
|
||||
/* block is divided into top and bottom halves */
|
||||
split = 0;
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
flags = (B[y * 2 + 1] << 8) | B[y * 2];
|
||||
if (y == 4)
|
||||
split = 4;
|
||||
|
||||
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2)
|
||||
*frame++ = P[split + ((flags >> shifter) & 0x03)];
|
||||
|
||||
frame += s->width - 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xb (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
/* 64-color encoding (each pixel in block is a different color) */
|
||||
CHECK_STREAM (len, 128);
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
for (x = 0; x < 8; ++x) {
|
||||
*frame++ = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xc (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned short pix;
|
||||
|
||||
/* 16-color block encoding: each 2x2 block is a different color */
|
||||
CHECK_STREAM (len, 32);
|
||||
|
||||
for (y = 0; y < 8; y += 2) {
|
||||
for (x = 0; x < 8; x += 2) {
|
||||
pix = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
*(frame + x) = pix;
|
||||
*(frame + x + 1) = pix;
|
||||
*(frame + s->width + x) = pix;
|
||||
*(frame + s->width + x + 1) = pix;
|
||||
}
|
||||
frame += s->width * 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xd (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned short P[4];
|
||||
unsigned char index = 0;
|
||||
|
||||
/* 4-color block encoding: each 4x4 block is a different color */
|
||||
CHECK_STREAM (len, 8);
|
||||
|
||||
P[0] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[1] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[2] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[3] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
if (y < 4)
|
||||
index = 0;
|
||||
else
|
||||
index = 2;
|
||||
|
||||
for (x = 0; x < 8; ++x) {
|
||||
if (x == 4)
|
||||
++index;
|
||||
*frame++ = P[index];
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xe (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned short pix;
|
||||
|
||||
/* 1-color encoding: the whole block is 1 solid color */
|
||||
CHECK_STREAM (len, 2);
|
||||
|
||||
pix = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
for (x = 0; x < 8; ++x) {
|
||||
*frame++ = pix;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xf (const GstMveDemuxStream * s, unsigned short *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned short P[2];
|
||||
|
||||
/* dithered encoding */
|
||||
CHECK_STREAM (len, 4);
|
||||
|
||||
P[0] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
P[1] = PIXEL (*data);
|
||||
(*data) += 2;
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
for (x = 0; x < 4; ++x) {
|
||||
*frame++ = P[y & 1];
|
||||
*frame++ = P[(y & 1) ^ 1];
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ipvideo_decode_frame16 (const GstMveDemuxStream * s, const unsigned char *data,
|
||||
unsigned short len)
|
||||
{
|
||||
int rc = 0;
|
||||
int x, y, xx, yy;
|
||||
int index = 0;
|
||||
unsigned short offset;
|
||||
unsigned char opcode;
|
||||
unsigned short *frame;
|
||||
const unsigned char *data2;
|
||||
unsigned short len2;
|
||||
|
||||
CHECK_STREAM (&len, 2);
|
||||
|
||||
offset = (data[1] << 8) | data[0];
|
||||
data2 = data + offset;
|
||||
len2 = len - offset + 2;
|
||||
data += 2;
|
||||
|
||||
frame = (unsigned short *) s->back_buf1;
|
||||
|
||||
/* decoding is done in 8x8 blocks */
|
||||
xx = s->width >> 3;
|
||||
yy = s->height >> 3;
|
||||
|
||||
for (y = 0; y < yy; ++y) {
|
||||
for (x = 0; x < xx; ++x) {
|
||||
/* decoding map contains 4 bits of information per 8x8 block */
|
||||
/* bottom nibble first, then top nibble */
|
||||
if (index & 1)
|
||||
opcode = s->code_map[index >> 1] >> 4;
|
||||
else
|
||||
opcode = s->code_map[index >> 1] & 0x0F;
|
||||
++index;
|
||||
|
||||
/* GST_DEBUG ("block @ (%3d, %3d): encoding 0x%X, data ptr @ %p",
|
||||
x, y, opcode, data); */
|
||||
|
||||
switch (opcode) {
|
||||
case 0x0:
|
||||
/* copy a block from the previous frame */
|
||||
rc = ipvideo_copy_block (s, frame, frame +
|
||||
((unsigned short *) s->back_buf2 -
|
||||
(unsigned short *) s->back_buf1), 0);
|
||||
break;
|
||||
case 0x1:
|
||||
/* copy block from 2 frames ago; since we switched the back
|
||||
* buffers we don't actually have to do anything here */
|
||||
break;
|
||||
case 0x2:
|
||||
rc = ipvideo_decode_0x2 (s, frame, &data2, &len2);
|
||||
break;
|
||||
case 0x3:
|
||||
rc = ipvideo_decode_0x3 (s, frame, &data2, &len2);
|
||||
break;
|
||||
case 0x4:
|
||||
rc = ipvideo_decode_0x4 (s, frame, &data2, &len2);
|
||||
break;
|
||||
case 0x5:
|
||||
rc = ipvideo_decode_0x5 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x6:
|
||||
/* mystery opcode? skip multiple blocks? */
|
||||
GST_WARNING ("encountered unsupported opcode 0x6");
|
||||
rc = -1;
|
||||
break;
|
||||
case 0x7:
|
||||
rc = ipvideo_decode_0x7 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x8:
|
||||
rc = ipvideo_decode_0x8 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x9:
|
||||
rc = ipvideo_decode_0x9 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0xa:
|
||||
rc = ipvideo_decode_0xa (s, frame, &data, &len);
|
||||
break;
|
||||
case 0xb:
|
||||
rc = ipvideo_decode_0xb (s, frame, &data, &len);
|
||||
break;
|
||||
case 0xc:
|
||||
rc = ipvideo_decode_0xc (s, frame, &data, &len);
|
||||
break;
|
||||
case 0xd:
|
||||
rc = ipvideo_decode_0xd (s, frame, &data, &len);
|
||||
break;
|
||||
case 0xe:
|
||||
rc = ipvideo_decode_0xe (s, frame, &data, &len);
|
||||
break;
|
||||
case 0xf:
|
||||
rc = ipvideo_decode_0xf (s, frame, &data, &len);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
frame += 8;
|
||||
}
|
||||
frame += 7 * s->width;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
802
gst/mve/mvevideodec8.c
Normal file
802
gst/mve/mvevideodec8.c
Normal file
|
@ -0,0 +1,802 @@
|
|||
/*
|
||||
* Interplay MVE Video Decoder (8 bit)
|
||||
* Copyright (C) 2003 the ffmpeg project, Mike Melanson
|
||||
* (C) 2006 Jens Granseuer
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* For more information about the Interplay MVE format, visit:
|
||||
* http://www.pcisys.net/~melanson/codecs/interplay-mve.txt
|
||||
*/
|
||||
|
||||
#include "gstmvedemux.h"
|
||||
#include <string.h>
|
||||
|
||||
#define CHECK_STREAM(l, n) \
|
||||
do { \
|
||||
if (G_UNLIKELY (*(l) < (n))) { \
|
||||
GST_ERROR ("wanted to read %d bytes from stream, %d available", (n), *(l)); \
|
||||
return -1; \
|
||||
} \
|
||||
*(l) -= (n); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* copy an 8x8 block from the stream to the frame buffer */
|
||||
static int
|
||||
ipvideo_copy_block (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char *src, int offset)
|
||||
{
|
||||
int i;
|
||||
long frame_offset;
|
||||
|
||||
frame_offset = frame - s->back_buf1 + offset;
|
||||
|
||||
if (G_UNLIKELY (frame_offset < 0)) {
|
||||
GST_ERROR ("frame offset < 0 (%ld)", frame_offset);
|
||||
return -1;
|
||||
} else if (G_UNLIKELY (frame_offset > s->max_block_offset)) {
|
||||
GST_ERROR ("frame offset above limit (%ld > %ld)",
|
||||
frame_offset, s->max_block_offset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
memcpy (frame, src, 8);
|
||||
frame += s->width;
|
||||
src += s->width;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x2 (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
unsigned char B;
|
||||
int x, y;
|
||||
int offset;
|
||||
|
||||
/* copy block from 2 frames ago using a motion vector */
|
||||
CHECK_STREAM (len, 1);
|
||||
B = *(*data)++;
|
||||
|
||||
if (B < 56) {
|
||||
x = 8 + (B % 7);
|
||||
y = B / 7;
|
||||
} else {
|
||||
x = -14 + ((B - 56) % 29);
|
||||
y = 8 + ((B - 56) / 29);
|
||||
}
|
||||
offset = y * s->width + x;
|
||||
|
||||
return ipvideo_copy_block (s, frame, frame + offset, offset);
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x3 (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
unsigned char B;
|
||||
int x, y;
|
||||
int offset;
|
||||
|
||||
/* copy 8x8 block from current frame from an up/left block */
|
||||
CHECK_STREAM (len, 1);
|
||||
B = *(*data)++;
|
||||
|
||||
if (B < 56) {
|
||||
x = -(8 + (B % 7));
|
||||
y = -(B / 7);
|
||||
} else {
|
||||
x = -(-14 + ((B - 56) % 29));
|
||||
y = -(8 + ((B - 56) / 29));
|
||||
}
|
||||
offset = y * s->width + x;
|
||||
|
||||
return ipvideo_copy_block (s, frame, frame + offset, offset);
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x4 (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
unsigned char B;
|
||||
int x, y;
|
||||
int offset;
|
||||
|
||||
/* copy a block from the previous frame */
|
||||
CHECK_STREAM (len, 1);
|
||||
B = *(*data)++;
|
||||
x = -8 + (B & 0x0F);
|
||||
y = -8 + (B >> 4);
|
||||
offset = y * s->width + x;
|
||||
|
||||
return ipvideo_copy_block (s, frame,
|
||||
frame + (s->back_buf2 - s->back_buf1) + offset, offset);
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x5 (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
signed char x, y;
|
||||
int offset;
|
||||
|
||||
/* copy a block from the previous frame using an expanded range */
|
||||
CHECK_STREAM (len, 2);
|
||||
|
||||
x = (signed char) *(*data)++;
|
||||
y = (signed char) *(*data)++;
|
||||
offset = y * s->width + x;
|
||||
|
||||
return ipvideo_copy_block (s, frame,
|
||||
frame + (s->back_buf2 - s->back_buf1) + offset, offset);
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x7 (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char P0, P1;
|
||||
unsigned int flags;
|
||||
int bitmask;
|
||||
|
||||
/* 2-color encoding */
|
||||
CHECK_STREAM (len, 2 + 2);
|
||||
|
||||
P0 = *(*data)++;
|
||||
P1 = *(*data)++;
|
||||
|
||||
if (P0 <= P1) {
|
||||
|
||||
/* need 8 more bytes from the stream */
|
||||
CHECK_STREAM (len, 8 - 2);
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
flags = *(*data)++;
|
||||
for (x = 0x01; x <= 0x80; x <<= 1) {
|
||||
if (flags & x)
|
||||
*frame++ = P1;
|
||||
else
|
||||
*frame++ = P0;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* need 2 more bytes from the stream */
|
||||
flags = ((*data)[1] << 8) | (*data)[0];
|
||||
(*data) += 2;
|
||||
bitmask = 0x0001;
|
||||
for (y = 0; y < 8; y += 2) {
|
||||
for (x = 0; x < 8; x += 2, bitmask <<= 1) {
|
||||
if (flags & bitmask) {
|
||||
*(frame + x) = P1;
|
||||
*(frame + x + 1) = P1;
|
||||
*(frame + s->width + x) = P1;
|
||||
*(frame + s->width + x + 1) = P1;
|
||||
} else {
|
||||
*(frame + x) = P0;
|
||||
*(frame + x + 1) = P0;
|
||||
*(frame + s->width + x) = P0;
|
||||
*(frame + s->width + x + 1) = P0;
|
||||
}
|
||||
}
|
||||
frame += s->width * 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x8 (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char P[8];
|
||||
unsigned char B[8];
|
||||
unsigned int flags = 0;
|
||||
unsigned int bitmask = 0;
|
||||
unsigned char P0 = 0, P1 = 0;
|
||||
int lower_half = 0;
|
||||
|
||||
/* 2-color encoding for each 4x4 quadrant, or 2-color encoding on
|
||||
* either top and bottom or left and right halves */
|
||||
CHECK_STREAM (len, 4 + 8);
|
||||
|
||||
P[0] = (*data)[0];
|
||||
P[1] = (*data)[1];
|
||||
B[0] = (*data)[2];
|
||||
B[1] = (*data)[3];
|
||||
(*data) += 4;
|
||||
|
||||
if (P[0] <= P[1]) {
|
||||
|
||||
/* need 12 more bytes */
|
||||
CHECK_STREAM (len, 12 - 8);
|
||||
|
||||
P[2] = (*data)[0];
|
||||
P[3] = (*data)[1];
|
||||
B[2] = (*data)[2];
|
||||
B[3] = (*data)[3];
|
||||
P[4] = (*data)[4];
|
||||
P[5] = (*data)[5];
|
||||
B[4] = (*data)[6];
|
||||
B[5] = (*data)[7];
|
||||
P[6] = (*data)[8];
|
||||
P[7] = (*data)[9];
|
||||
B[6] = (*data)[10];
|
||||
B[7] = (*data)[11];
|
||||
(*data) += 12;
|
||||
|
||||
flags =
|
||||
((B[0] & 0xF0) << 4) | ((B[4] & 0xF0) << 8) |
|
||||
((B[0] & 0x0F)) | ((B[4] & 0x0F) << 4) |
|
||||
((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
|
||||
((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
|
||||
bitmask = 0x00000001;
|
||||
lower_half = 0; /* still on top half */
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
/* time to reload flags? */
|
||||
if (y == 4) {
|
||||
flags =
|
||||
((B[2] & 0xF0) << 4) | ((B[6] & 0xF0) << 8) |
|
||||
((B[2] & 0x0F)) | ((B[6] & 0x0F) << 4) |
|
||||
((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
|
||||
((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
|
||||
bitmask = 0x00000001;
|
||||
lower_half = 2;
|
||||
}
|
||||
|
||||
/* get the pixel values ready for this quadrant */
|
||||
P0 = P[lower_half + 0];
|
||||
P1 = P[lower_half + 1];
|
||||
|
||||
for (x = 0; x < 8; ++x, bitmask <<= 1) {
|
||||
if (x == 4) {
|
||||
P0 = P[lower_half + 4];
|
||||
P1 = P[lower_half + 5];
|
||||
}
|
||||
|
||||
if (flags & bitmask)
|
||||
*frame++ = P1;
|
||||
else
|
||||
*frame++ = P0;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* need 8 more bytes */
|
||||
B[2] = (*data)[0];
|
||||
B[3] = (*data)[1];
|
||||
P[2] = (*data)[2];
|
||||
P[3] = (*data)[3];
|
||||
B[4] = (*data)[4];
|
||||
B[5] = (*data)[5];
|
||||
B[6] = (*data)[6];
|
||||
B[7] = (*data)[7];
|
||||
(*data) += 8;
|
||||
|
||||
if (P[2] <= P[3]) {
|
||||
|
||||
/* vertical split; left & right halves are 2-color encoded */
|
||||
|
||||
flags =
|
||||
((B[0] & 0xF0) << 4) | ((B[4] & 0xF0) << 8) |
|
||||
((B[0] & 0x0F)) | ((B[4] & 0x0F) << 4) |
|
||||
((B[1] & 0xF0) << 20) | ((B[5] & 0xF0) << 24) |
|
||||
((B[1] & 0x0F) << 16) | ((B[5] & 0x0F) << 20);
|
||||
bitmask = 0x00000001;
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
/* time to reload flags? */
|
||||
if (y == 4) {
|
||||
flags =
|
||||
((B[2] & 0xF0) << 4) | ((B[6] & 0xF0) << 8) |
|
||||
((B[2] & 0x0F)) | ((B[6] & 0x0F) << 4) |
|
||||
((B[3] & 0xF0) << 20) | ((B[7] & 0xF0) << 24) |
|
||||
((B[3] & 0x0F) << 16) | ((B[7] & 0x0F) << 20);
|
||||
bitmask = 0x00000001;
|
||||
}
|
||||
|
||||
/* get the pixel values ready for this half */
|
||||
P0 = P[0];
|
||||
P1 = P[1];
|
||||
|
||||
for (x = 0; x < 8; ++x, bitmask <<= 1) {
|
||||
if (x == 4) {
|
||||
P0 = P[2];
|
||||
P1 = P[3];
|
||||
}
|
||||
|
||||
if (flags & bitmask)
|
||||
*frame++ = P1;
|
||||
else
|
||||
*frame++ = P0;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* horizontal split; top & bottom halves are 2-color encoded */
|
||||
|
||||
P0 = P[0];
|
||||
P1 = P[1];
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
flags = B[y];
|
||||
if (y == 4) {
|
||||
P0 = P[2];
|
||||
P1 = P[3];
|
||||
}
|
||||
|
||||
for (bitmask = 0x01; bitmask <= 0x80; bitmask <<= 1) {
|
||||
|
||||
if (flags & bitmask)
|
||||
*frame++ = P1;
|
||||
else
|
||||
*frame++ = P0;
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0x9 (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char P[4];
|
||||
unsigned char B[4];
|
||||
unsigned long flags = 0;
|
||||
int shifter = 0;
|
||||
unsigned char pix;
|
||||
|
||||
/* 4-color encoding */
|
||||
CHECK_STREAM (len, 4 + 4);
|
||||
|
||||
P[0] = (*data)[0];
|
||||
P[1] = (*data)[1];
|
||||
P[2] = (*data)[2];
|
||||
P[3] = (*data)[3];
|
||||
(*data) += 4;
|
||||
|
||||
if ((P[0] <= P[1]) && (P[2] <= P[3])) {
|
||||
|
||||
/* 1 of 4 colors for each pixel, need 16 more bytes */
|
||||
CHECK_STREAM (len, 16 - 4);
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
/* get the next set of 8 2-bit flags */
|
||||
flags = ((*data)[1] << 8) | (*data)[0];
|
||||
(*data) += 2;
|
||||
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
|
||||
*frame++ = P[(flags >> shifter) & 0x03];
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else if ((P[0] <= P[1]) && (P[2] > P[3])) {
|
||||
|
||||
/* 1 of 4 colors for each 2x2 block, need 4 more bytes */
|
||||
B[0] = (*data)[0];
|
||||
B[1] = (*data)[1];
|
||||
B[2] = (*data)[2];
|
||||
B[3] = (*data)[3];
|
||||
(*data) += 4;
|
||||
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
|
||||
shifter = 0;
|
||||
|
||||
for (y = 0; y < 8; y += 2) {
|
||||
for (x = 0; x < 8; x += 2, shifter += 2) {
|
||||
pix = P[(flags >> shifter) & 0x03];
|
||||
*(frame + x) = pix;
|
||||
*(frame + x + 1) = pix;
|
||||
*(frame + s->width + x) = pix;
|
||||
*(frame + s->width + x + 1) = pix;
|
||||
}
|
||||
frame += s->width * 2;
|
||||
}
|
||||
|
||||
} else if ((P[0] > P[1]) && (P[2] <= P[3])) {
|
||||
|
||||
/* 1 of 4 colors for each 2x1 block, need 8 more bytes */
|
||||
CHECK_STREAM (len, 8 - 4);
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
/* time to reload flags? */
|
||||
if ((y == 0) || (y == 4)) {
|
||||
B[0] = (*data)[0];
|
||||
B[1] = (*data)[1];
|
||||
B[2] = (*data)[2];
|
||||
B[3] = (*data)[3];
|
||||
(*data) += 4;
|
||||
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
|
||||
shifter = 0;
|
||||
}
|
||||
for (x = 0; x < 8; x += 2, shifter += 2) {
|
||||
pix = P[(flags >> shifter) & 0x03];
|
||||
*(frame + x) = pix;
|
||||
*(frame + x + 1) = pix;
|
||||
}
|
||||
frame += s->width;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* 1 of 4 colors for each 1x2 block, need 8 more bytes */
|
||||
CHECK_STREAM (len, 8 - 4);
|
||||
|
||||
for (y = 0; y < 8; y += 2) {
|
||||
/* time to reload flags? */
|
||||
if ((y == 0) || (y == 4)) {
|
||||
B[0] = (*data)[0];
|
||||
B[1] = (*data)[1];
|
||||
B[2] = (*data)[2];
|
||||
B[3] = (*data)[3];
|
||||
(*data) += 4;
|
||||
flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
|
||||
shifter = 0;
|
||||
}
|
||||
for (x = 0; x < 8; ++x, shifter += 2) {
|
||||
pix = P[(flags >> shifter) & 0x03];
|
||||
*(frame + x) = pix;
|
||||
*(frame + s->width + x) = pix;
|
||||
}
|
||||
frame += s->width * 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xa (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char P[16];
|
||||
unsigned char B[16];
|
||||
int flags = 0;
|
||||
int shifter = 0;
|
||||
int index;
|
||||
int split;
|
||||
int lower_half;
|
||||
|
||||
/* 4-color encoding for each 4x4 quadrant, or 4-color encoding on
|
||||
* either top and bottom or left and right halves */
|
||||
CHECK_STREAM (len, 8 + 16);
|
||||
|
||||
P[0] = (*data)[0];
|
||||
P[1] = (*data)[1];
|
||||
P[2] = (*data)[2];
|
||||
P[3] = (*data)[3];
|
||||
B[0] = (*data)[4];
|
||||
B[1] = (*data)[5];
|
||||
B[2] = (*data)[6];
|
||||
B[3] = (*data)[7];
|
||||
(*data) += 8;
|
||||
|
||||
if (P[0] <= P[1]) {
|
||||
|
||||
/* 4-color encoding for each quadrant; need 24 more bytes */
|
||||
CHECK_STREAM (len, 24 - 16);
|
||||
|
||||
for (y = 4; y < 16; y += 4) {
|
||||
for (x = y; x < y + 4; ++x)
|
||||
P[x] = *(*data)++;
|
||||
for (x = y; x < y + 4; ++x)
|
||||
B[x] = *(*data)++;
|
||||
}
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
lower_half = (y >= 4) ? 4 : 0;
|
||||
flags = (B[y + 8] << 8) | B[y];
|
||||
|
||||
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
|
||||
split = (x >= 4) ? 8 : 0;
|
||||
index = split + lower_half + ((flags >> shifter) & 0x03);
|
||||
*frame++ = P[index];
|
||||
}
|
||||
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* 4-color encoding for either left and right or top and bottom
|
||||
* halves; need 16 more bytes */
|
||||
|
||||
B[4] = (*data)[0];
|
||||
B[5] = (*data)[1];
|
||||
B[6] = (*data)[2];
|
||||
B[7] = (*data)[3];
|
||||
P[4] = (*data)[4];
|
||||
P[5] = (*data)[5];
|
||||
P[6] = (*data)[6];
|
||||
P[7] = (*data)[7];
|
||||
(*data) += 8;
|
||||
memcpy (&B[8], *data, 8);
|
||||
(*data) += 8;
|
||||
|
||||
if (P[4] <= P[5]) {
|
||||
|
||||
/* block is divided into left and right halves */
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
flags = (B[y + 8] << 8) | B[y];
|
||||
split = 0;
|
||||
|
||||
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2) {
|
||||
if (x == 4)
|
||||
split = 4;
|
||||
*frame++ = P[split + ((flags >> shifter) & 0x03)];
|
||||
}
|
||||
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* block is divided into top and bottom halves */
|
||||
split = 0;
|
||||
for (y = 0; y < 8; ++y) {
|
||||
|
||||
flags = (B[y * 2 + 1] << 8) | B[y * 2];
|
||||
if (y == 4)
|
||||
split = 4;
|
||||
|
||||
for (x = 0, shifter = 0; x < 8; ++x, shifter += 2)
|
||||
*frame++ = P[split + ((flags >> shifter) & 0x03)];
|
||||
|
||||
frame += s->width - 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xb (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int y;
|
||||
|
||||
/* 64-color encoding (each pixel in block is a different color) */
|
||||
CHECK_STREAM (len, 64);
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
memcpy (frame, *data, 8);
|
||||
frame += s->width;
|
||||
(*data) += 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xc (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char pix;
|
||||
|
||||
/* 16-color block encoding: each 2x2 block is a different color */
|
||||
CHECK_STREAM (len, 16);
|
||||
|
||||
for (y = 0; y < 8; y += 2) {
|
||||
for (x = 0; x < 8; x += 2) {
|
||||
pix = *(*data)++;
|
||||
*(frame + x) = pix;
|
||||
*(frame + x + 1) = pix;
|
||||
*(frame + s->width + x) = pix;
|
||||
*(frame + s->width + x + 1) = pix;
|
||||
}
|
||||
frame += s->width * 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xd (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char P[4];
|
||||
unsigned char index = 0;
|
||||
|
||||
/* 4-color block encoding: each 4x4 block is a different color */
|
||||
CHECK_STREAM (len, 4);
|
||||
|
||||
P[0] = (*data)[0];
|
||||
P[1] = (*data)[1];
|
||||
P[2] = (*data)[2];
|
||||
P[3] = (*data)[3];
|
||||
(*data) += 4;
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
if (y < 4)
|
||||
index = 0;
|
||||
else
|
||||
index = 2;
|
||||
|
||||
for (x = 0; x < 8; ++x) {
|
||||
if (x == 4)
|
||||
++index;
|
||||
*frame++ = P[index];
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xe (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int y;
|
||||
unsigned char pix;
|
||||
|
||||
/* 1-color encoding: the whole block is 1 solid color */
|
||||
CHECK_STREAM (len, 1);
|
||||
pix = *(*data)++;
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
memset (frame, pix, 8);
|
||||
frame += s->width;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ipvideo_decode_0xf (const GstMveDemuxStream * s, unsigned char *frame,
|
||||
const unsigned char **data, unsigned short *len)
|
||||
{
|
||||
int x, y;
|
||||
unsigned char P[2];
|
||||
|
||||
/* dithered encoding */
|
||||
CHECK_STREAM (len, 2);
|
||||
|
||||
P[0] = *(*data)++;
|
||||
P[1] = *(*data)++;
|
||||
|
||||
for (y = 0; y < 8; ++y) {
|
||||
for (x = 0; x < 4; ++x) {
|
||||
*frame++ = P[y & 1];
|
||||
*frame++ = P[(y & 1) ^ 1];
|
||||
}
|
||||
frame += s->width - 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ipvideo_decode_frame8 (const GstMveDemuxStream * s, const unsigned char *data,
|
||||
unsigned short len)
|
||||
{
|
||||
int rc = 0;
|
||||
int x, y, xx, yy;
|
||||
int index = 0;
|
||||
unsigned char opcode;
|
||||
unsigned char *frame;
|
||||
|
||||
frame = s->back_buf1;
|
||||
|
||||
/* decoding is done in 8x8 blocks */
|
||||
xx = s->width >> 3;
|
||||
yy = s->height >> 3;
|
||||
|
||||
for (y = 0; y < yy; ++y) {
|
||||
for (x = 0; x < xx; ++x) {
|
||||
/* decoding map contains 4 bits of information per 8x8 block */
|
||||
/* bottom nibble first, then top nibble */
|
||||
if (index & 1)
|
||||
opcode = s->code_map[index >> 1] >> 4;
|
||||
else
|
||||
opcode = s->code_map[index >> 1] & 0x0F;
|
||||
++index;
|
||||
|
||||
/* GST_DEBUG ("block @ (%3d, %3d): encoding 0x%X, data ptr @ %p",
|
||||
x, y, opcode, data); */
|
||||
|
||||
switch (opcode) {
|
||||
case 0x00:
|
||||
/* copy a block from the previous frame */
|
||||
rc = ipvideo_copy_block (s, frame,
|
||||
frame + (s->back_buf2 - s->back_buf1), 0);
|
||||
break;
|
||||
case 0x01:
|
||||
/* copy block from 2 frames ago; since we switched the back
|
||||
* buffers we don't actually have to do anything here */
|
||||
break;
|
||||
case 0x02:
|
||||
rc = ipvideo_decode_0x2 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x03:
|
||||
rc = ipvideo_decode_0x3 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x04:
|
||||
rc = ipvideo_decode_0x4 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x05:
|
||||
rc = ipvideo_decode_0x5 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x06:
|
||||
/* mystery opcode? skip multiple blocks? */
|
||||
GST_WARNING ("encountered unsupported opcode 0x6");
|
||||
rc = -1;
|
||||
break;
|
||||
case 0x07:
|
||||
rc = ipvideo_decode_0x7 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x08:
|
||||
rc = ipvideo_decode_0x8 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x09:
|
||||
rc = ipvideo_decode_0x9 (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x0a:
|
||||
rc = ipvideo_decode_0xa (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x0b:
|
||||
rc = ipvideo_decode_0xb (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x0c:
|
||||
rc = ipvideo_decode_0xc (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x0d:
|
||||
rc = ipvideo_decode_0xd (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x0e:
|
||||
rc = ipvideo_decode_0xe (s, frame, &data, &len);
|
||||
break;
|
||||
case 0x0f:
|
||||
rc = ipvideo_decode_0xf (s, frame, &data, &len);
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
frame += 8;
|
||||
}
|
||||
frame += 7 * s->width;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
1649
gst/mve/mvevideoenc16.c
Normal file
1649
gst/mve/mvevideoenc16.c
Normal file
File diff suppressed because it is too large
Load diff
1733
gst/mve/mvevideoenc8.c
Normal file
1733
gst/mve/mvevideoenc8.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue