Update avcodec to 20080825
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27557 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -2,19 +2,21 @@
|
|||||||
* MACE decoder
|
* MACE decoder
|
||||||
* Copyright (c) 2002 Laszlo Torok <[email protected]>
|
* Copyright (c) 2002 Laszlo Torok <[email protected]>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -242,7 +244,8 @@ typedef struct MACEContext {
|
|||||||
static void chomp3(MACEContext *ctx,
|
static void chomp3(MACEContext *ctx,
|
||||||
uint8_t val,
|
uint8_t val,
|
||||||
const uint16_t tab1[],
|
const uint16_t tab1[],
|
||||||
const uint16_t tab2[][8])
|
const uint16_t tab2[][8],
|
||||||
|
uint32_t numChannels)
|
||||||
{
|
{
|
||||||
short current;
|
short current;
|
||||||
|
|
||||||
@@ -252,14 +255,15 @@ static void chomp3(MACEContext *ctx,
|
|||||||
else current+=ctx->lev;
|
else current+=ctx->lev;
|
||||||
ctx->lev=current-(current >> 3);
|
ctx->lev=current-(current >> 3);
|
||||||
// *ctx->outPtr++=current >> 8;
|
// *ctx->outPtr++=current >> 8;
|
||||||
*ctx->outPtr++=current;
|
*ctx->outPtr=current;
|
||||||
|
ctx->outPtr+=numChannels;
|
||||||
if ( ( ctx->index += tab1[val]-(ctx->index>>5) ) < 0 ) ctx->index = 0;
|
if ( ( ctx->index += tab1[val]-(ctx->index>>5) ) < 0 ) ctx->index = 0;
|
||||||
}
|
}
|
||||||
/* \\\ */
|
/* \\\ */
|
||||||
|
|
||||||
/* /// "Exp1to3()" */
|
/* /// "Exp1to3()" */
|
||||||
static void Exp1to3(MACEContext *ctx,
|
static void Exp1to3(MACEContext *ctx,
|
||||||
uint8_t *inBuffer,
|
const uint8_t *inBuffer,
|
||||||
void *outBuffer,
|
void *outBuffer,
|
||||||
uint32_t cnt,
|
uint32_t cnt,
|
||||||
uint32_t numChannels,
|
uint32_t numChannels,
|
||||||
@@ -281,13 +285,13 @@ static void Exp1to3(MACEContext *ctx,
|
|||||||
|
|
||||||
while (cnt>0) {
|
while (cnt>0) {
|
||||||
pkt=inBuffer[0];
|
pkt=inBuffer[0];
|
||||||
chomp3(ctx, pkt & 7, MACEtab1, MACEtab2);
|
chomp3(ctx, pkt & 7, MACEtab1, MACEtab2, numChannels);
|
||||||
chomp3(ctx,(pkt >> 3) & 3, MACEtab3, MACEtab4);
|
chomp3(ctx,(pkt >> 3) & 3, MACEtab3, MACEtab4, numChannels);
|
||||||
chomp3(ctx, pkt >> 5 , MACEtab1, MACEtab2);
|
chomp3(ctx, pkt >> 5 , MACEtab1, MACEtab2, numChannels);
|
||||||
pkt=inBuffer[1];
|
pkt=inBuffer[1];
|
||||||
chomp3(ctx, pkt & 7, MACEtab1, MACEtab2);
|
chomp3(ctx, pkt & 7, MACEtab1, MACEtab2, numChannels);
|
||||||
chomp3(ctx,(pkt >> 3) & 3, MACEtab3, MACEtab4);
|
chomp3(ctx,(pkt >> 3) & 3, MACEtab3, MACEtab4, numChannels);
|
||||||
chomp3(ctx, pkt >> 5 , MACEtab1, MACEtab2);
|
chomp3(ctx, pkt >> 5 , MACEtab1, MACEtab2, numChannels);
|
||||||
|
|
||||||
inBuffer+=numChannels*2;
|
inBuffer+=numChannels*2;
|
||||||
--cnt;
|
--cnt;
|
||||||
@@ -306,7 +310,8 @@ static void Exp1to3(MACEContext *ctx,
|
|||||||
static void chomp6(MACEContext *ctx,
|
static void chomp6(MACEContext *ctx,
|
||||||
uint8_t val,
|
uint8_t val,
|
||||||
const uint16_t tab1[],
|
const uint16_t tab1[],
|
||||||
const uint16_t tab2[][8])
|
const uint16_t tab2[][8],
|
||||||
|
uint32_t numChannels)
|
||||||
{
|
{
|
||||||
short current;
|
short current;
|
||||||
|
|
||||||
@@ -329,9 +334,10 @@ static void chomp6(MACEContext *ctx,
|
|||||||
|
|
||||||
// *ctx->outPtr++=(ctx->previous+ctx->prev2-((ctx->prev2-current) >> 2)) >> 8;
|
// *ctx->outPtr++=(ctx->previous+ctx->prev2-((ctx->prev2-current) >> 2)) >> 8;
|
||||||
// *ctx->outPtr++=(ctx->previous+current+((ctx->prev2-current) >> 2)) >> 8;
|
// *ctx->outPtr++=(ctx->previous+current+((ctx->prev2-current) >> 2)) >> 8;
|
||||||
*ctx->outPtr++=(ctx->previous+ctx->prev2-((ctx->prev2-current) >> 2));
|
*ctx->outPtr=(ctx->previous+ctx->prev2-((ctx->prev2-current) >> 2));
|
||||||
*ctx->outPtr++=(ctx->previous+current+((ctx->prev2-current) >> 2));
|
ctx->outPtr+=numChannels;
|
||||||
|
*ctx->outPtr=(ctx->previous+current+((ctx->prev2-current) >> 2));
|
||||||
|
ctx->outPtr+=numChannels;
|
||||||
ctx->prev2=ctx->previous;
|
ctx->prev2=ctx->previous;
|
||||||
ctx->previous=current;
|
ctx->previous=current;
|
||||||
|
|
||||||
@@ -341,7 +347,7 @@ static void chomp6(MACEContext *ctx,
|
|||||||
|
|
||||||
/* /// "Exp1to6()" */
|
/* /// "Exp1to6()" */
|
||||||
static void Exp1to6(MACEContext *ctx,
|
static void Exp1to6(MACEContext *ctx,
|
||||||
uint8_t *inBuffer,
|
const uint8_t *inBuffer,
|
||||||
void *outBuffer,
|
void *outBuffer,
|
||||||
uint32_t cnt,
|
uint32_t cnt,
|
||||||
uint32_t numChannels,
|
uint32_t numChannels,
|
||||||
@@ -366,9 +372,9 @@ static void Exp1to6(MACEContext *ctx,
|
|||||||
while (cnt>0) {
|
while (cnt>0) {
|
||||||
pkt=*inBuffer;
|
pkt=*inBuffer;
|
||||||
|
|
||||||
chomp6(ctx, pkt >> 5 , MACEtab1, MACEtab2);
|
chomp6(ctx, pkt >> 5 , MACEtab1, MACEtab2, numChannels);
|
||||||
chomp6(ctx,(pkt >> 3) & 3, MACEtab3, MACEtab4);
|
chomp6(ctx,(pkt >> 3) & 3, MACEtab3, MACEtab4, numChannels);
|
||||||
chomp6(ctx, pkt & 7, MACEtab1, MACEtab2);
|
chomp6(ctx, pkt & 7, MACEtab1, MACEtab2, numChannels);
|
||||||
|
|
||||||
inBuffer+=numChannels;
|
inBuffer+=numChannels;
|
||||||
--cnt;
|
--cnt;
|
||||||
@@ -386,16 +392,17 @@ static void Exp1to6(MACEContext *ctx,
|
|||||||
}
|
}
|
||||||
/* \\\ */
|
/* \\\ */
|
||||||
|
|
||||||
static int mace_decode_init(AVCodecContext * avctx)
|
static av_cold int mace_decode_init(AVCodecContext * avctx)
|
||||||
{
|
{
|
||||||
if (avctx->channels > 2)
|
if (avctx->channels > 2)
|
||||||
return -1;
|
return -1;
|
||||||
|
avctx->sample_fmt = SAMPLE_FMT_S16;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mace_decode_frame(AVCodecContext *avctx,
|
static int mace_decode_frame(AVCodecContext *avctx,
|
||||||
void *data, int *data_size,
|
void *data, int *data_size,
|
||||||
uint8_t *buf, int buf_size)
|
const uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
short *samples;
|
short *samples;
|
||||||
MACEContext *c = avctx->priv_data;
|
MACEContext *c = avctx->priv_data;
|
||||||
@@ -403,25 +410,20 @@ static int mace_decode_frame(AVCodecContext *avctx,
|
|||||||
samples = (short *)data;
|
samples = (short *)data;
|
||||||
switch (avctx->codec->id) {
|
switch (avctx->codec->id) {
|
||||||
case CODEC_ID_MACE3:
|
case CODEC_ID_MACE3:
|
||||||
#ifdef DEBUG
|
dprintf(avctx, "mace_decode_frame[3]()");
|
||||||
puts("mace_decode_frame[3]()");
|
Exp1to3(c, buf, samples, buf_size / 2 / avctx->channels, avctx->channels, 1);
|
||||||
#endif
|
|
||||||
Exp1to3(c, buf, samples, buf_size / 2, avctx->channels, 1);
|
|
||||||
if (avctx->channels == 2)
|
if (avctx->channels == 2)
|
||||||
Exp1to3(c, buf, samples+1, buf_size / 2, 2, 2);
|
Exp1to3(c, buf, samples+1, buf_size / 2 / 2, 2, 2);
|
||||||
*data_size = 2 * 3 * buf_size;
|
*data_size = 2 * 3 * buf_size;
|
||||||
break;
|
break;
|
||||||
case CODEC_ID_MACE6:
|
case CODEC_ID_MACE6:
|
||||||
#ifdef DEBUG
|
dprintf(avctx, "mace_decode_frame[6]()");
|
||||||
puts("mace_decode_frame[6]()");
|
Exp1to6(c, buf, samples, buf_size / avctx->channels, avctx->channels, 1);
|
||||||
#endif
|
|
||||||
Exp1to6(c, buf, samples, buf_size, avctx->channels, 1);
|
|
||||||
if (avctx->channels == 2)
|
if (avctx->channels == 2)
|
||||||
Exp1to6(c, buf, samples+1, buf_size, 2, 2);
|
Exp1to6(c, buf, samples+1, buf_size / 2, 2, 2);
|
||||||
*data_size = 2 * 6 * buf_size;
|
*data_size = 2 * 6 * buf_size;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*data_size = 0;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return buf_size;
|
return buf_size;
|
||||||
@@ -436,6 +438,7 @@ AVCodec mace3_decoder = {
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
mace_decode_frame,
|
mace_decode_frame,
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("MACE (Macintosh Audio Compression/Expansion) 3:1"),
|
||||||
};
|
};
|
||||||
|
|
||||||
AVCodec mace6_decoder = {
|
AVCodec mace6_decoder = {
|
||||||
@@ -447,5 +450,6 @@ AVCodec mace6_decoder = {
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
mace_decode_frame,
|
mace_decode_frame,
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("MACE (Macintosh Audio Compression/Expansion) 6:1"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* simple math operations
|
||||||
|
* Copyright (c) 2001, 2002 Fabrice Bellard.
|
||||||
|
* Copyright (c) 2006 Michael Niedermayer <[email protected]> et al
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#ifndef FFMPEG_MATHOPS_H
|
||||||
|
#define FFMPEG_MATHOPS_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#ifdef ARCH_X86_32
|
||||||
|
|
||||||
|
#include "i386/mathops.h"
|
||||||
|
|
||||||
|
#elif defined(ARCH_ARMV4L)
|
||||||
|
|
||||||
|
#include "armv4l/mathops.h"
|
||||||
|
|
||||||
|
#elif defined(ARCH_POWERPC)
|
||||||
|
|
||||||
|
#include "ppc/mathops.h"
|
||||||
|
|
||||||
|
#elif defined(ARCH_BFIN)
|
||||||
|
|
||||||
|
#include "bfin/mathops.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* generic implementation */
|
||||||
|
|
||||||
|
#ifndef MULL
|
||||||
|
# define MULL(a,b) (((int64_t)(a) * (int64_t)(b)) >> FRAC_BITS)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MULH
|
||||||
|
//gcc 3.4 creates an incredibly bloated mess out of this
|
||||||
|
//# define MULH(a,b) (((int64_t)(a) * (int64_t)(b))>>32)
|
||||||
|
|
||||||
|
static av_always_inline int MULH(int a, int b){
|
||||||
|
return ((int64_t)(a) * (int64_t)(b))>>32;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MUL64
|
||||||
|
# define MUL64(a,b) ((int64_t)(a) * (int64_t)(b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAC64
|
||||||
|
# define MAC64(d, a, b) ((d) += MUL64(a, b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MLS64
|
||||||
|
# define MLS64(d, a, b) ((d) -= MUL64(a, b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* signed 16x16 -> 32 multiply add accumulate */
|
||||||
|
#ifndef MAC16
|
||||||
|
# define MAC16(rt, ra, rb) rt += (ra) * (rb)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* signed 16x16 -> 32 multiply */
|
||||||
|
#ifndef MUL16
|
||||||
|
# define MUL16(ra, rb) ((ra) * (rb))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MLS16
|
||||||
|
# define MLS16(rt, ra, rb) ((rt) -= (ra) * (rb))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* FFMPEG_MATHOPS_H */
|
||||||
|
|
||||||
@@ -2,19 +2,21 @@
|
|||||||
* MDCT/IMDCT transforms
|
* MDCT/IMDCT transforms
|
||||||
* Copyright (c) 2002 Fabrice Bellard.
|
* Copyright (c) 2002 Fabrice Bellard.
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#include "dsputil.h"
|
#include "dsputil.h"
|
||||||
|
|
||||||
@@ -23,13 +25,52 @@
|
|||||||
* MDCT/IMDCT transforms.
|
* MDCT/IMDCT transforms.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Generate a Kaiser-Bessel Derived Window.
|
||||||
|
#define BESSEL_I0_ITER 50 // default: 50 iterations of Bessel I0 approximation
|
||||||
|
void ff_kbd_window_init(float *window, float alpha, int n)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
double sum = 0.0, bessel, tmp;
|
||||||
|
double local_window[n];
|
||||||
|
double alpha2 = (alpha * M_PI / n) * (alpha * M_PI / n);
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
tmp = i * (n - i) * alpha2;
|
||||||
|
bessel = 1.0;
|
||||||
|
for (j = BESSEL_I0_ITER; j > 0; j--)
|
||||||
|
bessel = bessel * tmp / (j * j) + 1;
|
||||||
|
sum += bessel;
|
||||||
|
local_window[i] = sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
sum++;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
window[i] = sqrt(local_window[i] / sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_ALIGNED(16, float, ff_sine_128 [ 128]);
|
||||||
|
DECLARE_ALIGNED(16, float, ff_sine_256 [ 256]);
|
||||||
|
DECLARE_ALIGNED(16, float, ff_sine_512 [ 512]);
|
||||||
|
DECLARE_ALIGNED(16, float, ff_sine_1024[1024]);
|
||||||
|
DECLARE_ALIGNED(16, float, ff_sine_2048[2048]);
|
||||||
|
float *ff_sine_windows[5] = {
|
||||||
|
ff_sine_128, ff_sine_256, ff_sine_512, ff_sine_1024, ff_sine_2048,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate a sine window.
|
||||||
|
void ff_sine_window_init(float *window, int n) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < n; i++)
|
||||||
|
window[i] = sin((i + 0.5) / (2 * n) * M_PI);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init MDCT or IMDCT computation.
|
* init MDCT or IMDCT computation.
|
||||||
*/
|
*/
|
||||||
int ff_mdct_init(MDCTContext *s, int nbits, int inverse)
|
int ff_mdct_init(MDCTContext *s, int nbits, int inverse)
|
||||||
{
|
{
|
||||||
int n, n4, i;
|
int n, n4, i;
|
||||||
float alpha;
|
double alpha;
|
||||||
|
|
||||||
memset(s, 0, sizeof(*s));
|
memset(s, 0, sizeof(*s));
|
||||||
n = 1 << nbits;
|
n = 1 << nbits;
|
||||||
@@ -48,7 +89,7 @@ int ff_mdct_init(MDCTContext *s, int nbits, int inverse)
|
|||||||
s->tcos[i] = -cos(alpha);
|
s->tcos[i] = -cos(alpha);
|
||||||
s->tsin[i] = -sin(alpha);
|
s->tsin[i] = -sin(alpha);
|
||||||
}
|
}
|
||||||
if (fft_init(&s->fft, s->nbits - 2, inverse) < 0)
|
if (ff_fft_init(&s->fft, s->nbits - 2, inverse) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
@@ -60,29 +101,28 @@ int ff_mdct_init(MDCTContext *s, int nbits, int inverse)
|
|||||||
/* complex multiplication: p = a * b */
|
/* complex multiplication: p = a * b */
|
||||||
#define CMUL(pre, pim, are, aim, bre, bim) \
|
#define CMUL(pre, pim, are, aim, bre, bim) \
|
||||||
{\
|
{\
|
||||||
float _are = (are);\
|
FFTSample _are = (are);\
|
||||||
float _aim = (aim);\
|
FFTSample _aim = (aim);\
|
||||||
float _bre = (bre);\
|
FFTSample _bre = (bre);\
|
||||||
float _bim = (bim);\
|
FFTSample _bim = (bim);\
|
||||||
(pre) = _are * _bre - _aim * _bim;\
|
(pre) = _are * _bre - _aim * _bim;\
|
||||||
(pim) = _are * _bim + _aim * _bre;\
|
(pim) = _are * _bim + _aim * _bre;\
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute inverse MDCT of size N = 2^nbits
|
* Compute the middle half of the inverse MDCT of size N = 2^nbits,
|
||||||
* @param output N samples
|
* thus excluding the parts that can be derived by symmetry
|
||||||
|
* @param output N/2 samples
|
||||||
* @param input N/2 samples
|
* @param input N/2 samples
|
||||||
* @param tmp N/2 samples
|
|
||||||
*/
|
*/
|
||||||
void ff_imdct_calc(MDCTContext *s, FFTSample *output,
|
void ff_imdct_half_c(MDCTContext *s, FFTSample *output, const FFTSample *input)
|
||||||
const FFTSample *input, FFTSample *tmp)
|
|
||||||
{
|
{
|
||||||
int k, n8, n4, n2, n, j;
|
int k, n8, n4, n2, n, j;
|
||||||
const uint16_t *revtab = s->fft.revtab;
|
const uint16_t *revtab = s->fft.revtab;
|
||||||
const FFTSample *tcos = s->tcos;
|
const FFTSample *tcos = s->tcos;
|
||||||
const FFTSample *tsin = s->tsin;
|
const FFTSample *tsin = s->tsin;
|
||||||
const FFTSample *in1, *in2;
|
const FFTSample *in1, *in2;
|
||||||
FFTComplex *z = (FFTComplex *)tmp;
|
FFTComplex *z = (FFTComplex *)output;
|
||||||
|
|
||||||
n = 1 << s->nbits;
|
n = 1 << s->nbits;
|
||||||
n2 = n >> 1;
|
n2 = n >> 1;
|
||||||
@@ -98,25 +138,39 @@ void ff_imdct_calc(MDCTContext *s, FFTSample *output,
|
|||||||
in1 += 2;
|
in1 += 2;
|
||||||
in2 -= 2;
|
in2 -= 2;
|
||||||
}
|
}
|
||||||
fft_calc(&s->fft, z);
|
ff_fft_calc(&s->fft, z);
|
||||||
|
|
||||||
/* post rotation + reordering */
|
/* post rotation + reordering */
|
||||||
/* XXX: optimize */
|
output += n4;
|
||||||
for(k = 0; k < n4; k++) {
|
|
||||||
CMUL(z[k].re, z[k].im, z[k].re, z[k].im, tcos[k], tsin[k]);
|
|
||||||
}
|
|
||||||
for(k = 0; k < n8; k++) {
|
for(k = 0; k < n8; k++) {
|
||||||
output[2*k] = -z[n8 + k].im;
|
FFTSample r0, i0, r1, i1;
|
||||||
output[n2-1-2*k] = z[n8 + k].im;
|
CMUL(r0, i1, z[n8-k-1].im, z[n8-k-1].re, tsin[n8-k-1], tcos[n8-k-1]);
|
||||||
|
CMUL(r1, i0, z[n8+k ].im, z[n8+k ].re, tsin[n8+k ], tcos[n8+k ]);
|
||||||
|
z[n8-k-1].re = r0;
|
||||||
|
z[n8-k-1].im = i0;
|
||||||
|
z[n8+k ].re = r1;
|
||||||
|
z[n8+k ].im = i1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
output[2*k+1] = z[n8-1-k].re;
|
/**
|
||||||
output[n2-1-2*k-1] = -z[n8-1-k].re;
|
* Compute inverse MDCT of size N = 2^nbits
|
||||||
|
* @param output N samples
|
||||||
|
* @param input N/2 samples
|
||||||
|
* @param tmp N/2 samples
|
||||||
|
*/
|
||||||
|
void ff_imdct_calc_c(MDCTContext *s, FFTSample *output, const FFTSample *input)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
int n = 1 << s->nbits;
|
||||||
|
int n2 = n >> 1;
|
||||||
|
int n4 = n >> 2;
|
||||||
|
|
||||||
output[n2 + 2*k]=-z[k+n8].re;
|
ff_imdct_half_c(s, output+n4, input);
|
||||||
output[n-1- 2*k]=-z[k+n8].re;
|
|
||||||
|
|
||||||
output[n2 + 2*k+1]=z[n8-k-1].im;
|
for(k = 0; k < n4; k++) {
|
||||||
output[n-2 - 2 * k] = z[n8-k-1].im;
|
output[k] = -output[n2-k-1];
|
||||||
|
output[n-k-1] = output[n2+k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,15 +180,14 @@ void ff_imdct_calc(MDCTContext *s, FFTSample *output,
|
|||||||
* @param out N/2 samples
|
* @param out N/2 samples
|
||||||
* @param tmp temporary storage of N/2 samples
|
* @param tmp temporary storage of N/2 samples
|
||||||
*/
|
*/
|
||||||
void ff_mdct_calc(MDCTContext *s, FFTSample *out,
|
void ff_mdct_calc(MDCTContext *s, FFTSample *out, const FFTSample *input)
|
||||||
const FFTSample *input, FFTSample *tmp)
|
|
||||||
{
|
{
|
||||||
int i, j, n, n8, n4, n2, n3;
|
int i, j, n, n8, n4, n2, n3;
|
||||||
FFTSample re, im, re1, im1;
|
FFTSample re, im;
|
||||||
const uint16_t *revtab = s->fft.revtab;
|
const uint16_t *revtab = s->fft.revtab;
|
||||||
const FFTSample *tcos = s->tcos;
|
const FFTSample *tcos = s->tcos;
|
||||||
const FFTSample *tsin = s->tsin;
|
const FFTSample *tsin = s->tsin;
|
||||||
FFTComplex *x = (FFTComplex *)tmp;
|
FFTComplex *x = (FFTComplex *)out;
|
||||||
|
|
||||||
n = 1 << s->nbits;
|
n = 1 << s->nbits;
|
||||||
n2 = n >> 1;
|
n2 = n >> 1;
|
||||||
@@ -155,15 +208,17 @@ void ff_mdct_calc(MDCTContext *s, FFTSample *out,
|
|||||||
CMUL(x[j].re, x[j].im, re, im, -tcos[n8 + i], tsin[n8 + i]);
|
CMUL(x[j].re, x[j].im, re, im, -tcos[n8 + i], tsin[n8 + i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fft_calc(&s->fft, x);
|
ff_fft_calc(&s->fft, x);
|
||||||
|
|
||||||
/* post rotation */
|
/* post rotation */
|
||||||
for(i=0;i<n4;i++) {
|
for(i=0;i<n8;i++) {
|
||||||
re = x[i].re;
|
FFTSample r0, i0, r1, i1;
|
||||||
im = x[i].im;
|
CMUL(i1, r0, x[n8-i-1].re, x[n8-i-1].im, -tsin[n8-i-1], -tcos[n8-i-1]);
|
||||||
CMUL(re1, im1, re, im, -tsin[i], -tcos[i]);
|
CMUL(i0, r1, x[n8+i ].re, x[n8+i ].im, -tsin[n8+i ], -tcos[n8+i ]);
|
||||||
out[2*i] = im1;
|
x[n8-i-1].re = r0;
|
||||||
out[n2-1-2*i] = re1;
|
x[n8-i-1].im = i0;
|
||||||
|
x[n8+i ].re = r1;
|
||||||
|
x[n8+i ].im = i1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,5 +226,5 @@ void ff_mdct_end(MDCTContext *s)
|
|||||||
{
|
{
|
||||||
av_freep(&s->tcos);
|
av_freep(&s->tcos);
|
||||||
av_freep(&s->tsin);
|
av_freep(&s->tsin);
|
||||||
fft_end(&s->fft);
|
ff_fft_end(&s->fft);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,41 @@
|
|||||||
/*
|
/*
|
||||||
* PSX MDEC codec
|
* Sony PlayStation MDEC (Motion DECoder)
|
||||||
* Copyright (c) 2003 Michael Niedermayer
|
* Copyright (c) 2003 Michael Niedermayer
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* based upon code from Sebastian Jedruszkiewicz <[email protected]>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
* based upon code from Sebastian Jedruszkiewicz <[email protected]>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file mdec.c
|
* @file mdec.c
|
||||||
* PSX MDEC codec.
|
* Sony PlayStation MDEC (Motion DECoder)
|
||||||
* This is very similar to intra only MPEG1.
|
* This is very similar to intra-only MPEG-1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "avcodec.h"
|
#include "avcodec.h"
|
||||||
#include "dsputil.h"
|
#include "dsputil.h"
|
||||||
#include "mpegvideo.h"
|
#include "mpegvideo.h"
|
||||||
|
#include "mpeg12.h"
|
||||||
//#undef NDEBUG
|
|
||||||
//#include <assert.h>
|
|
||||||
|
|
||||||
typedef struct MDECContext{
|
typedef struct MDECContext{
|
||||||
AVCodecContext *avctx;
|
AVCodecContext *avctx;
|
||||||
DSPContext dsp;
|
DSPContext dsp;
|
||||||
AVFrame picture;
|
AVFrame picture;
|
||||||
PutBitContext pb;
|
|
||||||
GetBitContext gb;
|
GetBitContext gb;
|
||||||
ScanTable scantable;
|
ScanTable scantable;
|
||||||
int version;
|
int version;
|
||||||
@@ -45,25 +44,25 @@ typedef struct MDECContext{
|
|||||||
int mb_width;
|
int mb_width;
|
||||||
int mb_height;
|
int mb_height;
|
||||||
int mb_x, mb_y;
|
int mb_x, mb_y;
|
||||||
DCTELEM __align8 block[6][64];
|
DECLARE_ALIGNED_16(DCTELEM, block[6][64]);
|
||||||
uint16_t __align8 intra_matrix[64];
|
DECLARE_ALIGNED_8(uint16_t, intra_matrix[64]);
|
||||||
int __align8 q_intra_matrix[64];
|
DECLARE_ALIGNED_8(int, q_intra_matrix[64]);
|
||||||
uint8_t *bitstream_buffer;
|
uint8_t *bitstream_buffer;
|
||||||
int bitstream_buffer_size;
|
unsigned int bitstream_buffer_size;
|
||||||
int block_last_index[6];
|
int block_last_index[6];
|
||||||
} MDECContext;
|
} MDECContext;
|
||||||
|
|
||||||
//very similar to mpeg1
|
//very similar to MPEG-1
|
||||||
static inline int mdec_decode_block_intra(MDECContext *a, DCTELEM *block, int n)
|
static inline int mdec_decode_block_intra(MDECContext *a, DCTELEM *block, int n)
|
||||||
{
|
{
|
||||||
int level, diff, i, j, run;
|
int level, diff, i, j, run;
|
||||||
int component;
|
int component;
|
||||||
RLTable *rl = &rl_mpeg1;
|
RLTable *rl = &ff_rl_mpeg1;
|
||||||
uint8_t * const scantable= a->scantable.permutated;
|
uint8_t * const scantable= a->scantable.permutated;
|
||||||
const uint16_t *quant_matrix= ff_mpeg1_default_intra_matrix;
|
const uint16_t *quant_matrix= ff_mpeg1_default_intra_matrix;
|
||||||
const int qscale= a->qscale;
|
const int qscale= a->qscale;
|
||||||
|
|
||||||
/* DC coef */
|
/* DC coefficient */
|
||||||
if(a->version==2){
|
if(a->version==2){
|
||||||
block[0]= 2*get_sbits(&a->gb, 10) + 1024;
|
block[0]= 2*get_sbits(&a->gb, 10) + 1024;
|
||||||
}else{
|
}else{
|
||||||
@@ -78,10 +77,10 @@ static inline int mdec_decode_block_intra(MDECContext *a, DCTELEM *block, int n)
|
|||||||
i = 0;
|
i = 0;
|
||||||
{
|
{
|
||||||
OPEN_READER(re, &a->gb);
|
OPEN_READER(re, &a->gb);
|
||||||
/* now quantify & encode AC coefs */
|
/* now quantify & encode AC coefficients */
|
||||||
for(;;) {
|
for(;;) {
|
||||||
UPDATE_CACHE(re, &a->gb);
|
UPDATE_CACHE(re, &a->gb);
|
||||||
GET_RL_VLC(level, run, re, &a->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2);
|
GET_RL_VLC(level, run, re, &a->gb, rl->rl_vlc[0], TEX_VLC_BITS, 2, 0);
|
||||||
|
|
||||||
if(level == 127){
|
if(level == 127){
|
||||||
break;
|
break;
|
||||||
@@ -89,7 +88,6 @@ static inline int mdec_decode_block_intra(MDECContext *a, DCTELEM *block, int n)
|
|||||||
i += run;
|
i += run;
|
||||||
j = scantable[i];
|
j = scantable[i];
|
||||||
level= (level*qscale*quant_matrix[j])>>3;
|
level= (level*qscale*quant_matrix[j])>>3;
|
||||||
// level= (level-1)|1;
|
|
||||||
level = (level ^ SHOW_SBITS(re, &a->gb, 1)) - SHOW_SBITS(re, &a->gb, 1);
|
level = (level ^ SHOW_SBITS(re, &a->gb, 1)) - SHOW_SBITS(re, &a->gb, 1);
|
||||||
LAST_SKIP_BITS(re, &a->gb, 1);
|
LAST_SKIP_BITS(re, &a->gb, 1);
|
||||||
} else {
|
} else {
|
||||||
@@ -156,20 +154,13 @@ static inline void idct_put(MDECContext *a, int mb_x, int mb_y){
|
|||||||
|
|
||||||
static int decode_frame(AVCodecContext *avctx,
|
static int decode_frame(AVCodecContext *avctx,
|
||||||
void *data, int *data_size,
|
void *data, int *data_size,
|
||||||
uint8_t *buf, int buf_size)
|
const uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
MDECContext * const a = avctx->priv_data;
|
MDECContext * const a = avctx->priv_data;
|
||||||
AVFrame *picture = data;
|
AVFrame *picture = data;
|
||||||
AVFrame * const p= (AVFrame*)&a->picture;
|
AVFrame * const p= &a->picture;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
*data_size = 0;
|
|
||||||
|
|
||||||
/* special case for last picture */
|
|
||||||
if (buf_size == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p->data[0])
|
if(p->data[0])
|
||||||
avctx->release_buffer(avctx, p);
|
avctx->release_buffer(avctx, p);
|
||||||
|
|
||||||
@@ -178,11 +169,8 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
|
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
p->pict_type= I_TYPE;
|
p->pict_type= FF_I_TYPE;
|
||||||
p->key_frame= 1;
|
p->key_frame= 1;
|
||||||
a->last_dc[0]=
|
|
||||||
a->last_dc[1]=
|
|
||||||
a->last_dc[2]= 0;
|
|
||||||
|
|
||||||
a->bitstream_buffer= av_fast_realloc(a->bitstream_buffer, &a->bitstream_buffer_size, buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
a->bitstream_buffer= av_fast_realloc(a->bitstream_buffer, &a->bitstream_buffer_size, buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
for(i=0; i<buf_size; i+=2){
|
for(i=0; i<buf_size; i+=2){
|
||||||
@@ -197,7 +185,9 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
a->qscale= get_bits(&a->gb, 16);
|
a->qscale= get_bits(&a->gb, 16);
|
||||||
a->version= get_bits(&a->gb, 16);
|
a->version= get_bits(&a->gb, 16);
|
||||||
|
|
||||||
// printf("qscale:%d (0x%X), version:%d (0x%X)\n", a->qscale, a->qscale, a->version, a->version);
|
a->last_dc[0]=
|
||||||
|
a->last_dc[1]=
|
||||||
|
a->last_dc[2]= 128;
|
||||||
|
|
||||||
for(a->mb_x=0; a->mb_x<a->mb_width; a->mb_x++){
|
for(a->mb_x=0; a->mb_x<a->mb_width; a->mb_x++){
|
||||||
for(a->mb_y=0; a->mb_y<a->mb_height; a->mb_y++){
|
for(a->mb_y=0; a->mb_y<a->mb_height; a->mb_y++){
|
||||||
@@ -208,57 +198,49 @@ static int decode_frame(AVCodecContext *avctx,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// p->quality= (32 + a->inv_qscale/2)/a->inv_qscale;
|
p->quality= a->qscale * FF_QP2LAMBDA;
|
||||||
// memset(p->qscale_table, p->quality, p->qstride*a->mb_height);
|
memset(p->qscale_table, a->qscale, p->qstride*a->mb_height);
|
||||||
|
|
||||||
*picture= *(AVFrame*)&a->picture;
|
*picture = a->picture;
|
||||||
*data_size = sizeof(AVPicture);
|
*data_size = sizeof(AVPicture);
|
||||||
|
|
||||||
emms_c();
|
|
||||||
|
|
||||||
return (get_bits_count(&a->gb)+31)/32*4;
|
return (get_bits_count(&a->gb)+31)/32*4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdec_common_init(AVCodecContext *avctx){
|
static av_cold void mdec_common_init(AVCodecContext *avctx){
|
||||||
MDECContext * const a = avctx->priv_data;
|
MDECContext * const a = avctx->priv_data;
|
||||||
|
|
||||||
dsputil_init(&a->dsp, avctx);
|
dsputil_init(&a->dsp, avctx);
|
||||||
|
|
||||||
a->mb_width = (avctx->width + 15) / 16;
|
a->mb_width = (avctx->coded_width + 15) / 16;
|
||||||
a->mb_height = (avctx->height + 15) / 16;
|
a->mb_height = (avctx->coded_height + 15) / 16;
|
||||||
|
|
||||||
avctx->coded_frame= (AVFrame*)&a->picture;
|
avctx->coded_frame= &a->picture;
|
||||||
a->avctx= avctx;
|
a->avctx= avctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decode_init(AVCodecContext *avctx){
|
static av_cold int decode_init(AVCodecContext *avctx){
|
||||||
MDECContext * const a = avctx->priv_data;
|
MDECContext * const a = avctx->priv_data;
|
||||||
AVFrame *p= (AVFrame*)&a->picture;
|
AVFrame *p= &a->picture;
|
||||||
|
|
||||||
mdec_common_init(avctx);
|
mdec_common_init(avctx);
|
||||||
init_vlcs();
|
ff_mpeg12_init_vlcs();
|
||||||
ff_init_scantable(a->dsp.idct_permutation, &a->scantable, ff_zigzag_direct);
|
ff_init_scantable(a->dsp.idct_permutation, &a->scantable, ff_zigzag_direct);
|
||||||
/*
|
|
||||||
for(i=0; i<64; i++){
|
|
||||||
int index= ff_zigzag_direct[i];
|
|
||||||
a->intra_matrix[i]= 64*ff_mpeg1_default_intra_matrix[index] / a->inv_qscale;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
p->qstride= a->mb_width;
|
p->qstride= a->mb_width;
|
||||||
p->qscale_table= av_mallocz( p->qstride * a->mb_height);
|
p->qscale_table= av_mallocz( p->qstride * a->mb_height);
|
||||||
|
avctx->pix_fmt= PIX_FMT_YUV420P;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decode_end(AVCodecContext *avctx){
|
static av_cold int decode_end(AVCodecContext *avctx){
|
||||||
MDECContext * const a = avctx->priv_data;
|
MDECContext * const a = avctx->priv_data;
|
||||||
|
|
||||||
av_freep(&a->bitstream_buffer);
|
av_freep(&a->bitstream_buffer);
|
||||||
av_freep(&a->picture.qscale_table);
|
av_freep(&a->picture.qscale_table);
|
||||||
a->bitstream_buffer_size=0;
|
a->bitstream_buffer_size=0;
|
||||||
|
|
||||||
avcodec_default_free_buffers(avctx);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,5 +254,6 @@ AVCodec mdec_decoder = {
|
|||||||
decode_end,
|
decode_end,
|
||||||
decode_frame,
|
decode_frame,
|
||||||
CODEC_CAP_DR1,
|
CODEC_CAP_DR1,
|
||||||
|
.long_name= NULL_IF_CONFIG_SMALL("Sony PlayStation MDEC (Motion DECoder)"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,390 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005 Ole André Vadla Ravnås <[email protected]>
|
||||||
|
* Copyright (C) 2008 Ramiro Polla <[email protected]>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "bitstream.h"
|
||||||
|
#include "bytestream.h"
|
||||||
|
#include "dsputil.h"
|
||||||
|
|
||||||
|
#define MIMIC_HEADER_SIZE 20
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
AVCodecContext *avctx;
|
||||||
|
|
||||||
|
int num_vblocks[3];
|
||||||
|
int num_hblocks[3];
|
||||||
|
|
||||||
|
uint8_t *swap_buf;
|
||||||
|
int swap_buf_size;
|
||||||
|
|
||||||
|
int cur_index;
|
||||||
|
int prev_index;
|
||||||
|
|
||||||
|
AVFrame buf_ptrs [16];
|
||||||
|
AVPicture flipped_ptrs[16];
|
||||||
|
|
||||||
|
DECLARE_ALIGNED_16(DCTELEM, dct_block[64]);
|
||||||
|
|
||||||
|
GetBitContext gb;
|
||||||
|
ScanTable scantable;
|
||||||
|
DSPContext dsp;
|
||||||
|
VLC vlc;
|
||||||
|
} MimicContext;
|
||||||
|
|
||||||
|
static const uint32_t huffcodes[] = {
|
||||||
|
0x0000000a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
||||||
|
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000b,
|
||||||
|
0x0000001b, 0x00000038, 0x00000078, 0x00000079, 0x0000007a, 0x000000f9,
|
||||||
|
0x000000fa, 0x000003fb, 0x000007f8, 0x000007f9, 0x000007fa, 0x000007fb,
|
||||||
|
0x00000ff8, 0x00000ff9, 0x00000001, 0x00000039, 0x0000007b, 0x000000fb,
|
||||||
|
0x000001f8, 0x000001f9, 0x00000ffa, 0x00000ffb, 0x00001ff8, 0x00001ff9,
|
||||||
|
0x00001ffa, 0x00001ffb, 0x00003ff8, 0x00003ff9, 0x00003ffa, 0x00000000,
|
||||||
|
0x00000004, 0x0000003a, 0x000001fa, 0x00003ffb, 0x00007ff8, 0x00007ff9,
|
||||||
|
0x00007ffa, 0x00007ffb, 0x0000fff8, 0x0000fff9, 0x0000fffa, 0x0000fffb,
|
||||||
|
0x0001fff8, 0x0001fff9, 0x0001fffa, 0x00000000, 0x0000000c, 0x000000f8,
|
||||||
|
0x000001fb, 0x0001fffb, 0x0003fff8, 0x0003fff9, 0x0003fffa, 0x0003fffb,
|
||||||
|
0x0007fff8, 0x0007fff9, 0x0007fffa, 0x0007fffb, 0x000ffff8, 0x000ffff9,
|
||||||
|
0x000ffffa, 0x00000000, 0x0000001a, 0x000003f8, 0x000ffffb, 0x001ffff8,
|
||||||
|
0x001ffff9, 0x001ffffa, 0x001ffffb, 0x003ffff8, 0x003ffff9, 0x003ffffa,
|
||||||
|
0x003ffffb, 0x007ffff8, 0x007ffff9, 0x007ffffa, 0x007ffffb, 0x00000000,
|
||||||
|
0x0000003b, 0x000003f9, 0x00fffff8, 0x00fffff9, 0x00fffffa, 0x00fffffb,
|
||||||
|
0x01fffff8, 0x01fffff9, 0x01fffffa, 0x01fffffb, 0x03fffff8, 0x03fffff9,
|
||||||
|
0x03fffffa, 0x03fffffb, 0x07fffff8, 0x00000000, 0x000003fa, 0x07fffff9,
|
||||||
|
0x07fffffa, 0x07fffffb, 0x0ffffff8, 0x0ffffff9, 0x0ffffffa, 0x0ffffffb,
|
||||||
|
0x1ffffff8, 0x1ffffff9, 0x1ffffffa, 0x1ffffffb, 0x3ffffff8, 0x3ffffff9,
|
||||||
|
0x3ffffffa,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t huffbits[] = {
|
||||||
|
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 2, 4, 5, 6, 7, 7, 7, 8,
|
||||||
|
8, 10, 11, 11, 11, 11, 12, 12, 2, 6, 7, 8,
|
||||||
|
9, 9, 12, 12, 13, 13, 13, 13, 14, 14, 14, 0,
|
||||||
|
3, 6, 9, 14, 15, 15, 15, 15, 16, 16, 16, 16,
|
||||||
|
17, 17, 17, 0, 4, 8, 9, 17, 18, 18, 18, 18,
|
||||||
|
19, 19, 19, 19, 20, 20, 20, 0, 5, 10, 20, 21,
|
||||||
|
21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 0,
|
||||||
|
6, 10, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26,
|
||||||
|
26, 26, 27, 0, 10, 27, 27, 27, 28, 28, 28, 28,
|
||||||
|
29, 29, 29, 29, 30, 30, 30,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t col_zag[64] = {
|
||||||
|
0, 8, 1, 2, 9, 16, 24, 17,
|
||||||
|
10, 3, 4, 11, 18, 25, 32, 40,
|
||||||
|
33, 26, 19, 12, 5, 6, 13, 20,
|
||||||
|
27, 34, 41, 48, 56, 49, 42, 35,
|
||||||
|
28, 21, 14, 7, 15, 22, 29, 36,
|
||||||
|
43, 50, 57, 58, 51, 44, 37, 30,
|
||||||
|
23, 31, 38, 45, 52, 59, 39, 46,
|
||||||
|
53, 60, 61, 54, 47, 55, 62, 63,
|
||||||
|
};
|
||||||
|
|
||||||
|
static av_cold int mimic_decode_init(AVCodecContext *avctx)
|
||||||
|
{
|
||||||
|
MimicContext *ctx = avctx->priv_data;
|
||||||
|
|
||||||
|
ctx->prev_index = 0;
|
||||||
|
ctx->cur_index = 15;
|
||||||
|
|
||||||
|
if(init_vlc(&ctx->vlc, 11, sizeof(huffbits)/sizeof(huffbits[0]),
|
||||||
|
huffbits, 1, 1, huffcodes, 4, 4, 0)) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "error initializing vlc table\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
dsputil_init(&ctx->dsp, avctx);
|
||||||
|
ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable, col_zag);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const static int8_t vlcdec_lookup[9][64] = {
|
||||||
|
{ 0, },
|
||||||
|
{ -1, 1, },
|
||||||
|
{ -3, 3, -2, 2, },
|
||||||
|
{ -7, 7, -6, 6, -5, 5, -4, 4, },
|
||||||
|
{ -15, 15, -14, 14, -13, 13, -12, 12,
|
||||||
|
-11, 11, -10, 10, -9, 9, -8, 8, },
|
||||||
|
{ -31, 31, -30, 30, -29, 29, -28, 28,
|
||||||
|
-27, 27, -26, 26, -25, 25, -24, 24,
|
||||||
|
-23, 23, -22, 22, -21, 21, -20, 20,
|
||||||
|
-19, 19, -18, 18, -17, 17, -16, 16, },
|
||||||
|
{ -63, 63, -62, 62, -61, 61, -60, 60,
|
||||||
|
-59, 59, -58, 58, -57, 57, -56, 56,
|
||||||
|
-55, 55, -54, 54, -53, 53, -52, 52,
|
||||||
|
-51, 51, -50, 50, -49, 49, -48, 48,
|
||||||
|
-47, 47, -46, 46, -45, 45, -44, 44,
|
||||||
|
-43, 43, -42, 42, -41, 41, -40, 40,
|
||||||
|
-39, 39, -38, 38, -37, 37, -36, 36,
|
||||||
|
-35, 35, -34, 34, -33, 33, -32, 32, },
|
||||||
|
{ -127, 127, -126, 126, -125, 125, -124, 124,
|
||||||
|
-123, 123, -122, 122, -121, 121, -120, 120,
|
||||||
|
-119, 119, -118, 118, -117, 117, -116, 116,
|
||||||
|
-115, 115, -114, 114, -113, 113, -112, 112,
|
||||||
|
-111, 111, -110, 110, -109, 109, -108, 108,
|
||||||
|
-107, 107, -106, 106, -105, 105, -104, 104,
|
||||||
|
-103, 103, -102, 102, -101, 101, -100, 100,
|
||||||
|
-99, 99, -98, 98, -97, 97, -96, 96, },
|
||||||
|
{ -95, 95, -94, 94, -93, 93, -92, 92,
|
||||||
|
-91, 91, -90, 90, -89, 89, -88, 88,
|
||||||
|
-87, 87, -86, 86, -85, 85, -84, 84,
|
||||||
|
-83, 83, -82, 82, -81, 81, -80, 80,
|
||||||
|
-79, 79, -78, 78, -77, 77, -76, 76,
|
||||||
|
-75, 75, -74, 74, -73, 73, -72, 72,
|
||||||
|
-71, 71, -70, 70, -69, 69, -68, 68,
|
||||||
|
-67, 67, -66, 66, -65, 65, -64, 64, },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int vlc_decode_block(MimicContext *ctx, int num_coeffs, int qscale)
|
||||||
|
{
|
||||||
|
DCTELEM *block = ctx->dct_block;
|
||||||
|
unsigned int pos;
|
||||||
|
|
||||||
|
memset(block, 0, 64 * sizeof(DCTELEM));
|
||||||
|
|
||||||
|
block[0] = get_bits(&ctx->gb, 8) << 3;
|
||||||
|
|
||||||
|
for(pos = 1; pos < num_coeffs; pos++) {
|
||||||
|
uint32_t vlc, num_bits;
|
||||||
|
int value;
|
||||||
|
int coeff;
|
||||||
|
|
||||||
|
vlc = get_vlc2(&ctx->gb, ctx->vlc.table, ctx->vlc.bits, 3);
|
||||||
|
if(!vlc) /* end-of-block code */
|
||||||
|
return 1;
|
||||||
|
if(vlc == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* pos_add and num_bits are coded in the vlc code */
|
||||||
|
pos += vlc&15; // pos_add
|
||||||
|
num_bits = vlc>>4; // num_bits
|
||||||
|
|
||||||
|
if(pos >= 64)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
value = get_bits(&ctx->gb, num_bits);
|
||||||
|
|
||||||
|
/* FFmpeg's IDCT behaves somewhat different from the original code, so
|
||||||
|
* a factor of 4 was added to the input */
|
||||||
|
|
||||||
|
coeff = vlcdec_lookup[num_bits][value];
|
||||||
|
if(pos<3)
|
||||||
|
coeff <<= 4;
|
||||||
|
else /* TODO Use >> 10 instead of / 1001 */
|
||||||
|
coeff = (coeff * qscale) / 1001;
|
||||||
|
|
||||||
|
block[ctx->scantable.permutated[pos]] = coeff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decode(MimicContext *ctx, int quality, int num_coeffs,
|
||||||
|
int is_iframe)
|
||||||
|
{
|
||||||
|
int y, x, plane;
|
||||||
|
|
||||||
|
for(plane = 0; plane < 3; plane++) {
|
||||||
|
const int is_chroma = !!plane;
|
||||||
|
const int qscale = av_clip(10000-quality,is_chroma?1000:2000,10000)<<2;
|
||||||
|
const int stride = ctx->flipped_ptrs[ctx->cur_index].linesize[plane];
|
||||||
|
const uint8_t *src = ctx->flipped_ptrs[ctx->prev_index].data[plane];
|
||||||
|
uint8_t *dst = ctx->flipped_ptrs[ctx->cur_index ].data[plane];
|
||||||
|
|
||||||
|
for(y = 0; y < ctx->num_vblocks[plane]; y++) {
|
||||||
|
for(x = 0; x < ctx->num_hblocks[plane]; x++) {
|
||||||
|
|
||||||
|
/* Check for a change condition in the current block.
|
||||||
|
* - iframes always change.
|
||||||
|
* - Luma plane changes on get_bits1 == 0
|
||||||
|
* - Chroma planes change on get_bits1 == 1 */
|
||||||
|
if(is_iframe || get_bits1(&ctx->gb) == is_chroma) {
|
||||||
|
|
||||||
|
/* Luma planes may use a backreference from the 15 last
|
||||||
|
* frames preceding the previous. (get_bits1 == 1)
|
||||||
|
* Chroma planes don't use backreferences. */
|
||||||
|
if(is_chroma || is_iframe || !get_bits1(&ctx->gb)) {
|
||||||
|
|
||||||
|
if(!vlc_decode_block(ctx, num_coeffs, qscale))
|
||||||
|
return 0;
|
||||||
|
ctx->dsp.idct_put(dst, stride, ctx->dct_block);
|
||||||
|
} else {
|
||||||
|
unsigned int backref = get_bits(&ctx->gb, 4);
|
||||||
|
int index = (ctx->cur_index+backref)&15;
|
||||||
|
uint8_t *p = ctx->flipped_ptrs[index].data[0];
|
||||||
|
|
||||||
|
if(p) {
|
||||||
|
p += src -
|
||||||
|
ctx->flipped_ptrs[ctx->prev_index].data[plane];
|
||||||
|
ctx->dsp.put_pixels_tab[1][0](dst, p, stride, 8);
|
||||||
|
} else {
|
||||||
|
av_log(ctx->avctx, AV_LOG_ERROR,
|
||||||
|
"No such backreference! Buggy sample.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx->dsp.put_pixels_tab[1][0](dst, src, stride, 8);
|
||||||
|
}
|
||||||
|
src += 8;
|
||||||
|
dst += 8;
|
||||||
|
}
|
||||||
|
src += (stride - ctx->num_hblocks[plane])<<3;
|
||||||
|
dst += (stride - ctx->num_hblocks[plane])<<3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flip the buffer upside-down and put it in the YVU order to match the
|
||||||
|
* way Mimic encodes frames.
|
||||||
|
*/
|
||||||
|
static void prepare_avpic(MimicContext *ctx, AVPicture *dst, AVPicture *src)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
dst->data[0] = src->data[0]+( ctx->avctx->height -1)*src->linesize[0];
|
||||||
|
dst->data[1] = src->data[2]+((ctx->avctx->height>>1)-1)*src->linesize[2];
|
||||||
|
dst->data[2] = src->data[1]+((ctx->avctx->height>>1)-1)*src->linesize[1];
|
||||||
|
for(i = 0; i < 3; i++)
|
||||||
|
dst->linesize[i] = -src->linesize[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mimic_decode_frame(AVCodecContext *avctx, void *data,
|
||||||
|
int *data_size, const uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
MimicContext *ctx = avctx->priv_data;
|
||||||
|
int is_pframe;
|
||||||
|
int width, height;
|
||||||
|
int quality, num_coeffs;
|
||||||
|
int swap_buf_size = buf_size - MIMIC_HEADER_SIZE;
|
||||||
|
|
||||||
|
if(buf_size < MIMIC_HEADER_SIZE) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "insufficient data\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf += 2; /* some constant (always 256) */
|
||||||
|
quality = bytestream_get_le16(&buf);
|
||||||
|
width = bytestream_get_le16(&buf);
|
||||||
|
height = bytestream_get_le16(&buf);
|
||||||
|
buf += 4; /* some constant */
|
||||||
|
is_pframe = bytestream_get_le32(&buf);
|
||||||
|
num_coeffs = bytestream_get_byte(&buf);
|
||||||
|
buf += 3; /* some constant */
|
||||||
|
|
||||||
|
if(!ctx->avctx) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(!(width == 160 && height == 120) &&
|
||||||
|
!(width == 320 && height == 240)) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "invalid width/height!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->avctx = avctx;
|
||||||
|
avctx->width = width;
|
||||||
|
avctx->height = height;
|
||||||
|
avctx->pix_fmt = PIX_FMT_YUV420P;
|
||||||
|
for(i = 0; i < 3; i++) {
|
||||||
|
ctx->num_vblocks[i] = -((-height) >> (3 + !!i));
|
||||||
|
ctx->num_hblocks[i] = width >> (3 + !!i) ;
|
||||||
|
}
|
||||||
|
} else if(width != ctx->avctx->width || height != ctx->avctx->height) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "resolution changing is not supported\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_pframe && !ctx->buf_ptrs[ctx->prev_index].data[0]) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "decoding must start with keyframe\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->buf_ptrs[ctx->cur_index].reference = 1;
|
||||||
|
if(avctx->get_buffer(avctx, &ctx->buf_ptrs[ctx->cur_index])) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_avpic(ctx, &ctx->flipped_ptrs[ctx->cur_index],
|
||||||
|
(AVPicture*) &ctx->buf_ptrs[ctx->cur_index]);
|
||||||
|
|
||||||
|
ctx->swap_buf = av_fast_realloc(ctx->swap_buf, &ctx->swap_buf_size,
|
||||||
|
swap_buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
if(!ctx->swap_buf)
|
||||||
|
return AVERROR_NOMEM;
|
||||||
|
|
||||||
|
ctx->dsp.bswap_buf((uint32_t*)ctx->swap_buf,
|
||||||
|
(const uint32_t*) buf,
|
||||||
|
swap_buf_size>>2);
|
||||||
|
init_get_bits(&ctx->gb, ctx->swap_buf, swap_buf_size << 3);
|
||||||
|
|
||||||
|
if(!decode(ctx, quality, num_coeffs, !is_pframe)) {
|
||||||
|
avctx->release_buffer(avctx, &ctx->buf_ptrs[ctx->cur_index]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->buf_ptrs[ctx->cur_index].pict_type = is_pframe ? FF_P_TYPE:FF_I_TYPE;
|
||||||
|
*(AVFrame*)data = ctx->buf_ptrs[ctx->cur_index];
|
||||||
|
*data_size = sizeof(AVFrame);
|
||||||
|
|
||||||
|
ctx->prev_index = ctx->cur_index;
|
||||||
|
ctx->cur_index--;
|
||||||
|
ctx->cur_index &= 15;
|
||||||
|
|
||||||
|
/* Only release frames that aren't used for backreferences anymore */
|
||||||
|
if(ctx->buf_ptrs[ctx->cur_index].data[0])
|
||||||
|
avctx->release_buffer(avctx, &ctx->buf_ptrs[ctx->cur_index]);
|
||||||
|
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_cold int mimic_decode_end(AVCodecContext *avctx)
|
||||||
|
{
|
||||||
|
MimicContext *ctx = avctx->priv_data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
av_free(ctx->swap_buf);
|
||||||
|
for(i = 0; i < 16; i++)
|
||||||
|
if(ctx->buf_ptrs[i].data[0])
|
||||||
|
avctx->release_buffer(avctx, &ctx->buf_ptrs[i]);
|
||||||
|
free_vlc(&ctx->vlc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVCodec mimic_decoder = {
|
||||||
|
"mimic",
|
||||||
|
CODEC_TYPE_VIDEO,
|
||||||
|
CODEC_ID_MIMIC,
|
||||||
|
sizeof(MimicContext),
|
||||||
|
mimic_decode_init,
|
||||||
|
NULL,
|
||||||
|
mimic_decode_end,
|
||||||
|
mimic_decode_frame,
|
||||||
|
CODEC_CAP_DR1,
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("Mimic"),
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* MJPEG encoder and decoder
|
||||||
|
* Copyright (c) 2000, 2001 Fabrice Bellard.
|
||||||
|
* Copyright (c) 2003 Alex Beregszaszi
|
||||||
|
* Copyright (c) 2003-2004 Michael Niedermayer
|
||||||
|
*
|
||||||
|
* Support for external huffman table, various fixes (AVID workaround),
|
||||||
|
* aspecting, new decode_frame mechanism and apple mjpeg-b support
|
||||||
|
* by Alex Beregszaszi
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mjpeg.h
|
||||||
|
* MJPEG encoder and decoder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FFMPEG_MJPEG_H
|
||||||
|
#define FFMPEG_MJPEG_H
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "bitstream.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* JPEG marker codes */
|
||||||
|
typedef enum {
|
||||||
|
/* start of frame */
|
||||||
|
SOF0 = 0xc0, /* baseline */
|
||||||
|
SOF1 = 0xc1, /* extended sequential, huffman */
|
||||||
|
SOF2 = 0xc2, /* progressive, huffman */
|
||||||
|
SOF3 = 0xc3, /* lossless, huffman */
|
||||||
|
|
||||||
|
SOF5 = 0xc5, /* differential sequential, huffman */
|
||||||
|
SOF6 = 0xc6, /* differential progressive, huffman */
|
||||||
|
SOF7 = 0xc7, /* differential lossless, huffman */
|
||||||
|
JPG = 0xc8, /* reserved for JPEG extension */
|
||||||
|
SOF9 = 0xc9, /* extended sequential, arithmetic */
|
||||||
|
SOF10 = 0xca, /* progressive, arithmetic */
|
||||||
|
SOF11 = 0xcb, /* lossless, arithmetic */
|
||||||
|
|
||||||
|
SOF13 = 0xcd, /* differential sequential, arithmetic */
|
||||||
|
SOF14 = 0xce, /* differential progressive, arithmetic */
|
||||||
|
SOF15 = 0xcf, /* differential lossless, arithmetic */
|
||||||
|
|
||||||
|
DHT = 0xc4, /* define huffman tables */
|
||||||
|
|
||||||
|
DAC = 0xcc, /* define arithmetic-coding conditioning */
|
||||||
|
|
||||||
|
/* restart with modulo 8 count "m" */
|
||||||
|
RST0 = 0xd0,
|
||||||
|
RST1 = 0xd1,
|
||||||
|
RST2 = 0xd2,
|
||||||
|
RST3 = 0xd3,
|
||||||
|
RST4 = 0xd4,
|
||||||
|
RST5 = 0xd5,
|
||||||
|
RST6 = 0xd6,
|
||||||
|
RST7 = 0xd7,
|
||||||
|
|
||||||
|
SOI = 0xd8, /* start of image */
|
||||||
|
EOI = 0xd9, /* end of image */
|
||||||
|
SOS = 0xda, /* start of scan */
|
||||||
|
DQT = 0xdb, /* define quantization tables */
|
||||||
|
DNL = 0xdc, /* define number of lines */
|
||||||
|
DRI = 0xdd, /* define restart interval */
|
||||||
|
DHP = 0xde, /* define hierarchical progression */
|
||||||
|
EXP = 0xdf, /* expand reference components */
|
||||||
|
|
||||||
|
APP0 = 0xe0,
|
||||||
|
APP1 = 0xe1,
|
||||||
|
APP2 = 0xe2,
|
||||||
|
APP3 = 0xe3,
|
||||||
|
APP4 = 0xe4,
|
||||||
|
APP5 = 0xe5,
|
||||||
|
APP6 = 0xe6,
|
||||||
|
APP7 = 0xe7,
|
||||||
|
APP8 = 0xe8,
|
||||||
|
APP9 = 0xe9,
|
||||||
|
APP10 = 0xea,
|
||||||
|
APP11 = 0xeb,
|
||||||
|
APP12 = 0xec,
|
||||||
|
APP13 = 0xed,
|
||||||
|
APP14 = 0xee,
|
||||||
|
APP15 = 0xef,
|
||||||
|
|
||||||
|
JPG0 = 0xf0,
|
||||||
|
JPG1 = 0xf1,
|
||||||
|
JPG2 = 0xf2,
|
||||||
|
JPG3 = 0xf3,
|
||||||
|
JPG4 = 0xf4,
|
||||||
|
JPG5 = 0xf5,
|
||||||
|
JPG6 = 0xf6,
|
||||||
|
SOF48 = 0xf7, ///< JPEG-LS
|
||||||
|
LSE = 0xf8, ///< JPEG-LS extension parameters
|
||||||
|
JPG9 = 0xf9,
|
||||||
|
JPG10 = 0xfa,
|
||||||
|
JPG11 = 0xfb,
|
||||||
|
JPG12 = 0xfc,
|
||||||
|
JPG13 = 0xfd,
|
||||||
|
|
||||||
|
COM = 0xfe, /* comment */
|
||||||
|
|
||||||
|
TEM = 0x01, /* temporary private use for arithmetic coding */
|
||||||
|
|
||||||
|
/* 0x02 -> 0xbf reserved */
|
||||||
|
} JPEG_MARKER;
|
||||||
|
|
||||||
|
static inline void put_marker(PutBitContext *p, int code)
|
||||||
|
{
|
||||||
|
put_bits(p, 8, 0xff);
|
||||||
|
put_bits(p, 8, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PREDICT(ret, topleft, top, left, predictor)\
|
||||||
|
switch(predictor){\
|
||||||
|
case 1: ret= left; break;\
|
||||||
|
case 2: ret= top; break;\
|
||||||
|
case 3: ret= topleft; break;\
|
||||||
|
case 4: ret= left + top - topleft; break;\
|
||||||
|
case 5: ret= left + ((top - topleft)>>1); break;\
|
||||||
|
case 6: ret= top + ((left - topleft)>>1); break;\
|
||||||
|
default:\
|
||||||
|
case 7: ret= (left + top)>>1; break;\
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const uint8_t ff_mjpeg_bits_dc_luminance[];
|
||||||
|
extern const uint8_t ff_mjpeg_val_dc[];
|
||||||
|
|
||||||
|
extern const uint8_t ff_mjpeg_bits_dc_chrominance[];
|
||||||
|
|
||||||
|
extern const uint8_t ff_mjpeg_bits_ac_luminance[];
|
||||||
|
extern const uint8_t ff_mjpeg_val_ac_luminance[];
|
||||||
|
|
||||||
|
extern const uint8_t ff_mjpeg_bits_ac_chrominance[];
|
||||||
|
extern const uint8_t ff_mjpeg_val_ac_chrominance[];
|
||||||
|
|
||||||
|
void ff_mjpeg_build_huffman_codes(uint8_t *huff_size, uint16_t *huff_code,
|
||||||
|
const uint8_t *bits_table,
|
||||||
|
const uint8_t *val_table);
|
||||||
|
|
||||||
|
#endif /* FFMPEG_MJPEG_H */
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* MJPEG parser
|
||||||
|
* Copyright (c) 2000, 2001 Fabrice Bellard.
|
||||||
|
* Copyright (c) 2003 Alex Beregszaszi
|
||||||
|
* Copyright (c) 2003-2004 Michael Niedermayer
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mjpeg_parser.c
|
||||||
|
* MJPEG parser.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finds the end of the current frame in the bitstream.
|
||||||
|
* @return the position of the first byte of the next frame, or -1
|
||||||
|
*/
|
||||||
|
static int find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size){
|
||||||
|
int vop_found, i;
|
||||||
|
uint16_t state;
|
||||||
|
|
||||||
|
vop_found= pc->frame_start_found;
|
||||||
|
state= pc->state;
|
||||||
|
|
||||||
|
i=0;
|
||||||
|
if(!vop_found){
|
||||||
|
for(i=0; i<buf_size; i++){
|
||||||
|
state= (state<<8) | buf[i];
|
||||||
|
if(state == 0xFFD8){
|
||||||
|
i++;
|
||||||
|
vop_found=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(vop_found){
|
||||||
|
/* EOF considered as end of frame */
|
||||||
|
if (buf_size == 0)
|
||||||
|
return 0;
|
||||||
|
for(; i<buf_size; i++){
|
||||||
|
state= (state<<8) | buf[i];
|
||||||
|
if(state == 0xFFD8){
|
||||||
|
pc->frame_start_found=0;
|
||||||
|
pc->state=0;
|
||||||
|
return i-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pc->frame_start_found= vop_found;
|
||||||
|
pc->state= state;
|
||||||
|
return END_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jpeg_parse(AVCodecParserContext *s,
|
||||||
|
AVCodecContext *avctx,
|
||||||
|
const uint8_t **poutbuf, int *poutbuf_size,
|
||||||
|
const uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
ParseContext *pc = s->priv_data;
|
||||||
|
int next;
|
||||||
|
|
||||||
|
next= find_frame_end(pc, buf, buf_size);
|
||||||
|
|
||||||
|
if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
|
||||||
|
*poutbuf = NULL;
|
||||||
|
*poutbuf_size = 0;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
*poutbuf = buf;
|
||||||
|
*poutbuf_size = buf_size;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AVCodecParser mjpeg_parser = {
|
||||||
|
{ CODEC_ID_MJPEG },
|
||||||
|
sizeof(ParseContext),
|
||||||
|
NULL,
|
||||||
|
jpeg_parse,
|
||||||
|
ff_parse_close,
|
||||||
|
};
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* MJPEG A dump header bitstream filter
|
||||||
|
* Copyright (c) 2006 Baptiste Coudurier.
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mjpega_dump_header_bsf.c
|
||||||
|
* MJPEG A dump header bitstream filter
|
||||||
|
* modifies bitstream to be decoded by quicktime
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "bytestream.h"
|
||||||
|
#include "mjpeg.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int mjpega_dump_header(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
|
||||||
|
uint8_t **poutbuf, int *poutbuf_size,
|
||||||
|
const uint8_t *buf, int buf_size, int keyframe)
|
||||||
|
{
|
||||||
|
uint8_t *poutbufp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (avctx->codec_id != CODEC_ID_MJPEG) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "mjpega bitstream filter only applies to mjpeg codec\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*poutbuf_size = 0;
|
||||||
|
*poutbuf = av_malloc(buf_size + 44 + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
poutbufp = *poutbuf;
|
||||||
|
bytestream_put_byte(&poutbufp, 0xff);
|
||||||
|
bytestream_put_byte(&poutbufp, SOI);
|
||||||
|
bytestream_put_byte(&poutbufp, 0xff);
|
||||||
|
bytestream_put_byte(&poutbufp, APP1);
|
||||||
|
bytestream_put_be16(&poutbufp, 42); /* size */
|
||||||
|
bytestream_put_be32(&poutbufp, 0);
|
||||||
|
bytestream_put_buffer(&poutbufp, "mjpg", 4);
|
||||||
|
bytestream_put_be32(&poutbufp, buf_size + 44); /* field size */
|
||||||
|
bytestream_put_be32(&poutbufp, buf_size + 44); /* pad field size */
|
||||||
|
bytestream_put_be32(&poutbufp, 0); /* next ptr */
|
||||||
|
|
||||||
|
for (i = 0; i < buf_size - 1; i++) {
|
||||||
|
if (buf[i] == 0xff) {
|
||||||
|
switch (buf[i + 1]) {
|
||||||
|
case DQT: /* quant off */
|
||||||
|
case DHT: /* huff off */
|
||||||
|
case SOF0: /* image off */
|
||||||
|
bytestream_put_be32(&poutbufp, i + 46);
|
||||||
|
break;
|
||||||
|
case SOS:
|
||||||
|
bytestream_put_be32(&poutbufp, i + 46); /* scan off */
|
||||||
|
bytestream_put_be32(&poutbufp, i + 46 + AV_RB16(buf + i + 2)); /* data off */
|
||||||
|
bytestream_put_buffer(&poutbufp, buf + 2, buf_size - 2); /* skip already written SOI */
|
||||||
|
*poutbuf_size = poutbufp - *poutbuf;
|
||||||
|
return 1;
|
||||||
|
case APP1:
|
||||||
|
if (i + 8 < buf_size && AV_RL32(buf + i + 8) == ff_get_fourcc("mjpg")) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "bitstream already formatted\n");
|
||||||
|
memcpy(*poutbuf, buf, buf_size);
|
||||||
|
*poutbuf_size = buf_size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_freep(poutbuf);
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "could not find SOS marker in bitstream\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVBitStreamFilter mjpega_dump_header_bsf = {
|
||||||
|
"mjpegadump",
|
||||||
|
0,
|
||||||
|
mjpega_dump_header,
|
||||||
|
};
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Apple MJPEG-B decoder
|
||||||
|
* Copyright (c) 2002 Alex Beregszaszi
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mjpegbdec.c
|
||||||
|
* Apple MJPEG-B decoder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "mjpeg.h"
|
||||||
|
#include "mjpegdec.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int mjpegb_decode_frame(AVCodecContext *avctx,
|
||||||
|
void *data, int *data_size,
|
||||||
|
const uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
MJpegDecodeContext *s = avctx->priv_data;
|
||||||
|
const uint8_t *buf_end, *buf_ptr;
|
||||||
|
AVFrame *picture = data;
|
||||||
|
GetBitContext hgb; /* for the header */
|
||||||
|
uint32_t dqt_offs, dht_offs, sof_offs, sos_offs, second_field_offs;
|
||||||
|
uint32_t field_size, sod_offs;
|
||||||
|
|
||||||
|
buf_ptr = buf;
|
||||||
|
buf_end = buf + buf_size;
|
||||||
|
|
||||||
|
read_header:
|
||||||
|
/* reset on every SOI */
|
||||||
|
s->restart_interval = 0;
|
||||||
|
s->restart_count = 0;
|
||||||
|
s->mjpb_skiptosod = 0;
|
||||||
|
|
||||||
|
init_get_bits(&hgb, buf_ptr, /*buf_size*/(buf_end - buf_ptr)*8);
|
||||||
|
|
||||||
|
skip_bits(&hgb, 32); /* reserved zeros */
|
||||||
|
|
||||||
|
if (get_bits_long(&hgb, 32) != MKBETAG('m','j','p','g'))
|
||||||
|
{
|
||||||
|
av_log(avctx, AV_LOG_WARNING, "not mjpeg-b (bad fourcc)\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
field_size = get_bits_long(&hgb, 32); /* field size */
|
||||||
|
av_log(avctx, AV_LOG_DEBUG, "field size: 0x%x\n", field_size);
|
||||||
|
skip_bits(&hgb, 32); /* padded field size */
|
||||||
|
second_field_offs = get_bits_long(&hgb, 32);
|
||||||
|
av_log(avctx, AV_LOG_DEBUG, "second field offs: 0x%x\n", second_field_offs);
|
||||||
|
|
||||||
|
dqt_offs = get_bits_long(&hgb, 32);
|
||||||
|
av_log(avctx, AV_LOG_DEBUG, "dqt offs: 0x%x\n", dqt_offs);
|
||||||
|
if (dqt_offs)
|
||||||
|
{
|
||||||
|
init_get_bits(&s->gb, buf_ptr+dqt_offs, (buf_end - (buf_ptr+dqt_offs))*8);
|
||||||
|
s->start_code = DQT;
|
||||||
|
ff_mjpeg_decode_dqt(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
dht_offs = get_bits_long(&hgb, 32);
|
||||||
|
av_log(avctx, AV_LOG_DEBUG, "dht offs: 0x%x\n", dht_offs);
|
||||||
|
if (dht_offs)
|
||||||
|
{
|
||||||
|
init_get_bits(&s->gb, buf_ptr+dht_offs, (buf_end - (buf_ptr+dht_offs))*8);
|
||||||
|
s->start_code = DHT;
|
||||||
|
ff_mjpeg_decode_dht(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
sof_offs = get_bits_long(&hgb, 32);
|
||||||
|
av_log(avctx, AV_LOG_DEBUG, "sof offs: 0x%x\n", sof_offs);
|
||||||
|
if (sof_offs)
|
||||||
|
{
|
||||||
|
init_get_bits(&s->gb, buf_ptr+sof_offs, (buf_end - (buf_ptr+sof_offs))*8);
|
||||||
|
s->start_code = SOF0;
|
||||||
|
if (ff_mjpeg_decode_sof(s) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sos_offs = get_bits_long(&hgb, 32);
|
||||||
|
av_log(avctx, AV_LOG_DEBUG, "sos offs: 0x%x\n", sos_offs);
|
||||||
|
sod_offs = get_bits_long(&hgb, 32);
|
||||||
|
av_log(avctx, AV_LOG_DEBUG, "sod offs: 0x%x\n", sod_offs);
|
||||||
|
if (sos_offs)
|
||||||
|
{
|
||||||
|
// init_get_bits(&s->gb, buf+sos_offs, (buf_end - (buf+sos_offs))*8);
|
||||||
|
init_get_bits(&s->gb, buf_ptr+sos_offs, field_size*8);
|
||||||
|
s->mjpb_skiptosod = (sod_offs - sos_offs - show_bits(&s->gb, 16));
|
||||||
|
s->start_code = SOS;
|
||||||
|
ff_mjpeg_decode_sos(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->interlaced) {
|
||||||
|
s->bottom_field ^= 1;
|
||||||
|
/* if not bottom field, do not output image yet */
|
||||||
|
if (s->bottom_field != s->interlace_polarity && second_field_offs)
|
||||||
|
{
|
||||||
|
buf_ptr = buf + second_field_offs;
|
||||||
|
second_field_offs = 0;
|
||||||
|
goto read_header;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//XXX FIXME factorize, this looks very similar to the EOI code
|
||||||
|
|
||||||
|
*picture= s->picture;
|
||||||
|
*data_size = sizeof(AVFrame);
|
||||||
|
|
||||||
|
if(!s->lossless){
|
||||||
|
picture->quality= FFMAX3(s->qscale[0], s->qscale[1], s->qscale[2]);
|
||||||
|
picture->qstride= 0;
|
||||||
|
picture->qscale_table= s->qscale_table;
|
||||||
|
memset(picture->qscale_table, picture->quality, (s->width+15)/16);
|
||||||
|
if(avctx->debug & FF_DEBUG_QP)
|
||||||
|
av_log(avctx, AV_LOG_DEBUG, "QP: %d\n", picture->quality);
|
||||||
|
picture->quality*= FF_QP2LAMBDA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf_ptr - buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVCodec mjpegb_decoder = {
|
||||||
|
"mjpegb",
|
||||||
|
CODEC_TYPE_VIDEO,
|
||||||
|
CODEC_ID_MJPEGB,
|
||||||
|
sizeof(MJpegDecodeContext),
|
||||||
|
ff_mjpeg_decode_init,
|
||||||
|
NULL,
|
||||||
|
ff_mjpeg_decode_end,
|
||||||
|
mjpegb_decode_frame,
|
||||||
|
CODEC_CAP_DR1,
|
||||||
|
NULL,
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("Apple MJPEG-B"),
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* MJPEG decoder
|
||||||
|
* Copyright (c) 2000, 2001 Fabrice Bellard.
|
||||||
|
* Copyright (c) 2003 Alex Beregszaszi
|
||||||
|
* Copyright (c) 2003-2004 Michael Niedermayer
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mjpegdec.h
|
||||||
|
* MJPEG decoder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FFMPEG_MJPEGDEC_H
|
||||||
|
#define FFMPEG_MJPEGDEC_H
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "bitstream.h"
|
||||||
|
#include "dsputil.h"
|
||||||
|
|
||||||
|
#define MAX_COMPONENTS 4
|
||||||
|
|
||||||
|
typedef struct MJpegDecodeContext {
|
||||||
|
AVCodecContext *avctx;
|
||||||
|
GetBitContext gb;
|
||||||
|
|
||||||
|
int start_code; /* current start code */
|
||||||
|
int buffer_size;
|
||||||
|
uint8_t *buffer;
|
||||||
|
|
||||||
|
int16_t quant_matrixes[4][64];
|
||||||
|
VLC vlcs[2][4];
|
||||||
|
int qscale[4]; ///< quantizer scale calculated from quant_matrixes
|
||||||
|
|
||||||
|
int org_height; /* size given at codec init */
|
||||||
|
int first_picture; /* true if decoding first picture */
|
||||||
|
int interlaced; /* true if interlaced */
|
||||||
|
int bottom_field; /* true if bottom field */
|
||||||
|
int lossless;
|
||||||
|
int ls;
|
||||||
|
int progressive;
|
||||||
|
int rgb;
|
||||||
|
int rct; /* standard rct */
|
||||||
|
int pegasus_rct; /* pegasus reversible colorspace transform */
|
||||||
|
int bits; /* bits per component */
|
||||||
|
|
||||||
|
int maxval;
|
||||||
|
int near; ///< near lossless bound (si 0 for lossless)
|
||||||
|
int t1,t2,t3;
|
||||||
|
int reset; ///< context halfing intervall ?rename
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
int mb_width, mb_height;
|
||||||
|
int nb_components;
|
||||||
|
int component_id[MAX_COMPONENTS];
|
||||||
|
int h_count[MAX_COMPONENTS]; /* horizontal and vertical count for each component */
|
||||||
|
int v_count[MAX_COMPONENTS];
|
||||||
|
int comp_index[MAX_COMPONENTS];
|
||||||
|
int dc_index[MAX_COMPONENTS];
|
||||||
|
int ac_index[MAX_COMPONENTS];
|
||||||
|
int nb_blocks[MAX_COMPONENTS];
|
||||||
|
int h_scount[MAX_COMPONENTS];
|
||||||
|
int v_scount[MAX_COMPONENTS];
|
||||||
|
int h_max, v_max; /* maximum h and v counts */
|
||||||
|
int quant_index[4]; /* quant table index for each component */
|
||||||
|
int last_dc[MAX_COMPONENTS]; /* last DEQUANTIZED dc (XXX: am I right to do that ?) */
|
||||||
|
AVFrame picture; /* picture structure */
|
||||||
|
int linesize[MAX_COMPONENTS]; ///< linesize << interlaced
|
||||||
|
int8_t *qscale_table;
|
||||||
|
DECLARE_ALIGNED_16(DCTELEM, block[64]);
|
||||||
|
ScanTable scantable;
|
||||||
|
DSPContext dsp;
|
||||||
|
|
||||||
|
int restart_interval;
|
||||||
|
int restart_count;
|
||||||
|
|
||||||
|
int buggy_avid;
|
||||||
|
int cs_itu601;
|
||||||
|
int interlace_polarity;
|
||||||
|
|
||||||
|
int mjpb_skiptosod;
|
||||||
|
|
||||||
|
int cur_scan; /* current scan, used by JPEG-LS */
|
||||||
|
} MJpegDecodeContext;
|
||||||
|
|
||||||
|
int ff_mjpeg_decode_init(AVCodecContext *avctx);
|
||||||
|
int ff_mjpeg_decode_end(AVCodecContext *avctx);
|
||||||
|
int ff_mjpeg_decode_frame(AVCodecContext *avctx,
|
||||||
|
void *data, int *data_size,
|
||||||
|
const uint8_t *buf, int buf_size);
|
||||||
|
int ff_mjpeg_decode_dqt(MJpegDecodeContext *s);
|
||||||
|
int ff_mjpeg_decode_dht(MJpegDecodeContext *s);
|
||||||
|
int ff_mjpeg_decode_sof(MJpegDecodeContext *s);
|
||||||
|
int ff_mjpeg_decode_sos(MJpegDecodeContext *s);
|
||||||
|
|
||||||
|
#endif /* FFMPEG_MJPEGDEC_H */
|
||||||
@@ -0,0 +1,459 @@
|
|||||||
|
/*
|
||||||
|
* MJPEG encoder
|
||||||
|
* Copyright (c) 2000, 2001 Fabrice Bellard.
|
||||||
|
* Copyright (c) 2003 Alex Beregszaszi
|
||||||
|
* Copyright (c) 2003-2004 Michael Niedermayer
|
||||||
|
*
|
||||||
|
* Support for external huffman table, various fixes (AVID workaround),
|
||||||
|
* aspecting, new decode_frame mechanism and apple mjpeg-b support
|
||||||
|
* by Alex Beregszaszi
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mjpegenc.c
|
||||||
|
* MJPEG encoder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "dsputil.h"
|
||||||
|
#include "mpegvideo.h"
|
||||||
|
#include "mjpeg.h"
|
||||||
|
#include "mjpegenc.h"
|
||||||
|
|
||||||
|
/* use two quantizer tables (one for luminance and one for chrominance) */
|
||||||
|
/* not yet working */
|
||||||
|
#undef TWOMATRIXES
|
||||||
|
|
||||||
|
|
||||||
|
av_cold int ff_mjpeg_encode_init(MpegEncContext *s)
|
||||||
|
{
|
||||||
|
MJpegContext *m;
|
||||||
|
|
||||||
|
m = av_malloc(sizeof(MJpegContext));
|
||||||
|
if (!m)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
s->min_qcoeff=-1023;
|
||||||
|
s->max_qcoeff= 1023;
|
||||||
|
|
||||||
|
/* build all the huffman tables */
|
||||||
|
ff_mjpeg_build_huffman_codes(m->huff_size_dc_luminance,
|
||||||
|
m->huff_code_dc_luminance,
|
||||||
|
ff_mjpeg_bits_dc_luminance,
|
||||||
|
ff_mjpeg_val_dc);
|
||||||
|
ff_mjpeg_build_huffman_codes(m->huff_size_dc_chrominance,
|
||||||
|
m->huff_code_dc_chrominance,
|
||||||
|
ff_mjpeg_bits_dc_chrominance,
|
||||||
|
ff_mjpeg_val_dc);
|
||||||
|
ff_mjpeg_build_huffman_codes(m->huff_size_ac_luminance,
|
||||||
|
m->huff_code_ac_luminance,
|
||||||
|
ff_mjpeg_bits_ac_luminance,
|
||||||
|
ff_mjpeg_val_ac_luminance);
|
||||||
|
ff_mjpeg_build_huffman_codes(m->huff_size_ac_chrominance,
|
||||||
|
m->huff_code_ac_chrominance,
|
||||||
|
ff_mjpeg_bits_ac_chrominance,
|
||||||
|
ff_mjpeg_val_ac_chrominance);
|
||||||
|
|
||||||
|
s->mjpeg_ctx = m;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_mjpeg_encode_close(MpegEncContext *s)
|
||||||
|
{
|
||||||
|
av_free(s->mjpeg_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* table_class: 0 = DC coef, 1 = AC coefs */
|
||||||
|
static int put_huffman_table(MpegEncContext *s, int table_class, int table_id,
|
||||||
|
const uint8_t *bits_table, const uint8_t *value_table)
|
||||||
|
{
|
||||||
|
PutBitContext *p = &s->pb;
|
||||||
|
int n, i;
|
||||||
|
|
||||||
|
put_bits(p, 4, table_class);
|
||||||
|
put_bits(p, 4, table_id);
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
for(i=1;i<=16;i++) {
|
||||||
|
n += bits_table[i];
|
||||||
|
put_bits(p, 8, bits_table[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0;i<n;i++)
|
||||||
|
put_bits(p, 8, value_table[i]);
|
||||||
|
|
||||||
|
return n + 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jpeg_table_header(MpegEncContext *s)
|
||||||
|
{
|
||||||
|
PutBitContext *p = &s->pb;
|
||||||
|
int i, j, size;
|
||||||
|
uint8_t *ptr;
|
||||||
|
|
||||||
|
/* quant matrixes */
|
||||||
|
put_marker(p, DQT);
|
||||||
|
#ifdef TWOMATRIXES
|
||||||
|
put_bits(p, 16, 2 + 2 * (1 + 64));
|
||||||
|
#else
|
||||||
|
put_bits(p, 16, 2 + 1 * (1 + 64));
|
||||||
|
#endif
|
||||||
|
put_bits(p, 4, 0); /* 8 bit precision */
|
||||||
|
put_bits(p, 4, 0); /* table 0 */
|
||||||
|
for(i=0;i<64;i++) {
|
||||||
|
j = s->intra_scantable.permutated[i];
|
||||||
|
put_bits(p, 8, s->intra_matrix[j]);
|
||||||
|
}
|
||||||
|
#ifdef TWOMATRIXES
|
||||||
|
put_bits(p, 4, 0); /* 8 bit precision */
|
||||||
|
put_bits(p, 4, 1); /* table 1 */
|
||||||
|
for(i=0;i<64;i++) {
|
||||||
|
j = s->intra_scantable.permutated[i];
|
||||||
|
put_bits(p, 8, s->chroma_intra_matrix[j]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* huffman table */
|
||||||
|
put_marker(p, DHT);
|
||||||
|
flush_put_bits(p);
|
||||||
|
ptr = pbBufPtr(p);
|
||||||
|
put_bits(p, 16, 0); /* patched later */
|
||||||
|
size = 2;
|
||||||
|
size += put_huffman_table(s, 0, 0, ff_mjpeg_bits_dc_luminance,
|
||||||
|
ff_mjpeg_val_dc);
|
||||||
|
size += put_huffman_table(s, 0, 1, ff_mjpeg_bits_dc_chrominance,
|
||||||
|
ff_mjpeg_val_dc);
|
||||||
|
|
||||||
|
size += put_huffman_table(s, 1, 0, ff_mjpeg_bits_ac_luminance,
|
||||||
|
ff_mjpeg_val_ac_luminance);
|
||||||
|
size += put_huffman_table(s, 1, 1, ff_mjpeg_bits_ac_chrominance,
|
||||||
|
ff_mjpeg_val_ac_chrominance);
|
||||||
|
AV_WB16(ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jpeg_put_comments(MpegEncContext *s)
|
||||||
|
{
|
||||||
|
PutBitContext *p = &s->pb;
|
||||||
|
int size;
|
||||||
|
uint8_t *ptr;
|
||||||
|
|
||||||
|
if (s->aspect_ratio_info /* && !lossless */)
|
||||||
|
{
|
||||||
|
/* JFIF header */
|
||||||
|
put_marker(p, APP0);
|
||||||
|
put_bits(p, 16, 16);
|
||||||
|
ff_put_string(p, "JFIF", 1); /* this puts the trailing zero-byte too */
|
||||||
|
put_bits(p, 16, 0x0201); /* v 1.02 */
|
||||||
|
put_bits(p, 8, 0); /* units type: 0 - aspect ratio */
|
||||||
|
put_bits(p, 16, s->avctx->sample_aspect_ratio.num);
|
||||||
|
put_bits(p, 16, s->avctx->sample_aspect_ratio.den);
|
||||||
|
put_bits(p, 8, 0); /* thumbnail width */
|
||||||
|
put_bits(p, 8, 0); /* thumbnail height */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* comment */
|
||||||
|
if(!(s->flags & CODEC_FLAG_BITEXACT)){
|
||||||
|
put_marker(p, COM);
|
||||||
|
flush_put_bits(p);
|
||||||
|
ptr = pbBufPtr(p);
|
||||||
|
put_bits(p, 16, 0); /* patched later */
|
||||||
|
ff_put_string(p, LIBAVCODEC_IDENT, 1);
|
||||||
|
size = strlen(LIBAVCODEC_IDENT)+3;
|
||||||
|
AV_WB16(ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( s->avctx->pix_fmt == PIX_FMT_YUV420P
|
||||||
|
||s->avctx->pix_fmt == PIX_FMT_YUV422P
|
||||||
|
||s->avctx->pix_fmt == PIX_FMT_YUV444P){
|
||||||
|
put_marker(p, COM);
|
||||||
|
flush_put_bits(p);
|
||||||
|
ptr = pbBufPtr(p);
|
||||||
|
put_bits(p, 16, 0); /* patched later */
|
||||||
|
ff_put_string(p, "CS=ITU601", 1);
|
||||||
|
size = strlen("CS=ITU601")+3;
|
||||||
|
AV_WB16(ptr, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_mjpeg_encode_picture_header(MpegEncContext *s)
|
||||||
|
{
|
||||||
|
const int lossless= s->avctx->codec_id != CODEC_ID_MJPEG;
|
||||||
|
|
||||||
|
put_marker(&s->pb, SOI);
|
||||||
|
|
||||||
|
jpeg_put_comments(s);
|
||||||
|
|
||||||
|
jpeg_table_header(s);
|
||||||
|
|
||||||
|
switch(s->avctx->codec_id){
|
||||||
|
case CODEC_ID_MJPEG: put_marker(&s->pb, SOF0 ); break;
|
||||||
|
case CODEC_ID_LJPEG: put_marker(&s->pb, SOF3 ); break;
|
||||||
|
default: assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
put_bits(&s->pb, 16, 17);
|
||||||
|
if(lossless && s->avctx->pix_fmt == PIX_FMT_RGB32)
|
||||||
|
put_bits(&s->pb, 8, 9); /* 9 bits/component RCT */
|
||||||
|
else
|
||||||
|
put_bits(&s->pb, 8, 8); /* 8 bits/component */
|
||||||
|
put_bits(&s->pb, 16, s->height);
|
||||||
|
put_bits(&s->pb, 16, s->width);
|
||||||
|
put_bits(&s->pb, 8, 3); /* 3 components */
|
||||||
|
|
||||||
|
/* Y component */
|
||||||
|
put_bits(&s->pb, 8, 1); /* component number */
|
||||||
|
put_bits(&s->pb, 4, s->mjpeg_hsample[0]); /* H factor */
|
||||||
|
put_bits(&s->pb, 4, s->mjpeg_vsample[0]); /* V factor */
|
||||||
|
put_bits(&s->pb, 8, 0); /* select matrix */
|
||||||
|
|
||||||
|
/* Cb component */
|
||||||
|
put_bits(&s->pb, 8, 2); /* component number */
|
||||||
|
put_bits(&s->pb, 4, s->mjpeg_hsample[1]); /* H factor */
|
||||||
|
put_bits(&s->pb, 4, s->mjpeg_vsample[1]); /* V factor */
|
||||||
|
#ifdef TWOMATRIXES
|
||||||
|
put_bits(&s->pb, 8, lossless ? 0 : 1); /* select matrix */
|
||||||
|
#else
|
||||||
|
put_bits(&s->pb, 8, 0); /* select matrix */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Cr component */
|
||||||
|
put_bits(&s->pb, 8, 3); /* component number */
|
||||||
|
put_bits(&s->pb, 4, s->mjpeg_hsample[2]); /* H factor */
|
||||||
|
put_bits(&s->pb, 4, s->mjpeg_vsample[2]); /* V factor */
|
||||||
|
#ifdef TWOMATRIXES
|
||||||
|
put_bits(&s->pb, 8, lossless ? 0 : 1); /* select matrix */
|
||||||
|
#else
|
||||||
|
put_bits(&s->pb, 8, 0); /* select matrix */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* scan header */
|
||||||
|
put_marker(&s->pb, SOS);
|
||||||
|
put_bits(&s->pb, 16, 12); /* length */
|
||||||
|
put_bits(&s->pb, 8, 3); /* 3 components */
|
||||||
|
|
||||||
|
/* Y component */
|
||||||
|
put_bits(&s->pb, 8, 1); /* index */
|
||||||
|
put_bits(&s->pb, 4, 0); /* DC huffman table index */
|
||||||
|
put_bits(&s->pb, 4, 0); /* AC huffman table index */
|
||||||
|
|
||||||
|
/* Cb component */
|
||||||
|
put_bits(&s->pb, 8, 2); /* index */
|
||||||
|
put_bits(&s->pb, 4, 1); /* DC huffman table index */
|
||||||
|
put_bits(&s->pb, 4, lossless ? 0 : 1); /* AC huffman table index */
|
||||||
|
|
||||||
|
/* Cr component */
|
||||||
|
put_bits(&s->pb, 8, 3); /* index */
|
||||||
|
put_bits(&s->pb, 4, 1); /* DC huffman table index */
|
||||||
|
put_bits(&s->pb, 4, lossless ? 0 : 1); /* AC huffman table index */
|
||||||
|
|
||||||
|
put_bits(&s->pb, 8, lossless ? s->avctx->prediction_method+1 : 0); /* Ss (not used) */
|
||||||
|
|
||||||
|
switch(s->avctx->codec_id){
|
||||||
|
case CODEC_ID_MJPEG: put_bits(&s->pb, 8, 63); break; /* Se (not used) */
|
||||||
|
case CODEC_ID_LJPEG: put_bits(&s->pb, 8, 0); break; /* not used */
|
||||||
|
default: assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
put_bits(&s->pb, 8, 0); /* Ah/Al (not used) */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void escape_FF(MpegEncContext *s, int start)
|
||||||
|
{
|
||||||
|
int size= put_bits_count(&s->pb) - start*8;
|
||||||
|
int i, ff_count;
|
||||||
|
uint8_t *buf= s->pb.buf + start;
|
||||||
|
int align= (-(size_t)(buf))&3;
|
||||||
|
|
||||||
|
assert((size&7) == 0);
|
||||||
|
size >>= 3;
|
||||||
|
|
||||||
|
ff_count=0;
|
||||||
|
for(i=0; i<size && i<align; i++){
|
||||||
|
if(buf[i]==0xFF) ff_count++;
|
||||||
|
}
|
||||||
|
for(; i<size-15; i+=16){
|
||||||
|
int acc, v;
|
||||||
|
|
||||||
|
v= *(uint32_t*)(&buf[i]);
|
||||||
|
acc= (((v & (v>>4))&0x0F0F0F0F)+0x01010101)&0x10101010;
|
||||||
|
v= *(uint32_t*)(&buf[i+4]);
|
||||||
|
acc+=(((v & (v>>4))&0x0F0F0F0F)+0x01010101)&0x10101010;
|
||||||
|
v= *(uint32_t*)(&buf[i+8]);
|
||||||
|
acc+=(((v & (v>>4))&0x0F0F0F0F)+0x01010101)&0x10101010;
|
||||||
|
v= *(uint32_t*)(&buf[i+12]);
|
||||||
|
acc+=(((v & (v>>4))&0x0F0F0F0F)+0x01010101)&0x10101010;
|
||||||
|
|
||||||
|
acc>>=4;
|
||||||
|
acc+= (acc>>16);
|
||||||
|
acc+= (acc>>8);
|
||||||
|
ff_count+= acc&0xFF;
|
||||||
|
}
|
||||||
|
for(; i<size; i++){
|
||||||
|
if(buf[i]==0xFF) ff_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ff_count==0) return;
|
||||||
|
|
||||||
|
/* skip put bits */
|
||||||
|
for(i=0; i<ff_count-3; i+=4)
|
||||||
|
put_bits(&s->pb, 32, 0);
|
||||||
|
put_bits(&s->pb, (ff_count-i)*8, 0);
|
||||||
|
flush_put_bits(&s->pb);
|
||||||
|
|
||||||
|
for(i=size-1; ff_count; i--){
|
||||||
|
int v= buf[i];
|
||||||
|
|
||||||
|
if(v==0xFF){
|
||||||
|
//printf("%d %d\n", i, ff_count);
|
||||||
|
buf[i+ff_count]= 0;
|
||||||
|
ff_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[i+ff_count]= v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_mjpeg_encode_stuffing(PutBitContext * pbc)
|
||||||
|
{
|
||||||
|
int length;
|
||||||
|
length= (-put_bits_count(pbc))&7;
|
||||||
|
if(length) put_bits(pbc, length, (1<<length)-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_mjpeg_encode_picture_trailer(MpegEncContext *s)
|
||||||
|
{
|
||||||
|
ff_mjpeg_encode_stuffing(&s->pb);
|
||||||
|
flush_put_bits(&s->pb);
|
||||||
|
|
||||||
|
assert((s->header_bits&7)==0);
|
||||||
|
|
||||||
|
escape_FF(s, s->header_bits>>3);
|
||||||
|
|
||||||
|
put_marker(&s->pb, EOI);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_mjpeg_encode_dc(MpegEncContext *s, int val,
|
||||||
|
uint8_t *huff_size, uint16_t *huff_code)
|
||||||
|
{
|
||||||
|
int mant, nbits;
|
||||||
|
|
||||||
|
if (val == 0) {
|
||||||
|
put_bits(&s->pb, huff_size[0], huff_code[0]);
|
||||||
|
} else {
|
||||||
|
mant = val;
|
||||||
|
if (val < 0) {
|
||||||
|
val = -val;
|
||||||
|
mant--;
|
||||||
|
}
|
||||||
|
|
||||||
|
nbits= av_log2_16bit(val) + 1;
|
||||||
|
|
||||||
|
put_bits(&s->pb, huff_size[nbits], huff_code[nbits]);
|
||||||
|
|
||||||
|
put_sbits(&s->pb, nbits, mant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void encode_block(MpegEncContext *s, DCTELEM *block, int n)
|
||||||
|
{
|
||||||
|
int mant, nbits, code, i, j;
|
||||||
|
int component, dc, run, last_index, val;
|
||||||
|
MJpegContext *m = s->mjpeg_ctx;
|
||||||
|
uint8_t *huff_size_ac;
|
||||||
|
uint16_t *huff_code_ac;
|
||||||
|
|
||||||
|
/* DC coef */
|
||||||
|
component = (n <= 3 ? 0 : (n&1) + 1);
|
||||||
|
dc = block[0]; /* overflow is impossible */
|
||||||
|
val = dc - s->last_dc[component];
|
||||||
|
if (n < 4) {
|
||||||
|
ff_mjpeg_encode_dc(s, val, m->huff_size_dc_luminance, m->huff_code_dc_luminance);
|
||||||
|
huff_size_ac = m->huff_size_ac_luminance;
|
||||||
|
huff_code_ac = m->huff_code_ac_luminance;
|
||||||
|
} else {
|
||||||
|
ff_mjpeg_encode_dc(s, val, m->huff_size_dc_chrominance, m->huff_code_dc_chrominance);
|
||||||
|
huff_size_ac = m->huff_size_ac_chrominance;
|
||||||
|
huff_code_ac = m->huff_code_ac_chrominance;
|
||||||
|
}
|
||||||
|
s->last_dc[component] = dc;
|
||||||
|
|
||||||
|
/* AC coefs */
|
||||||
|
|
||||||
|
run = 0;
|
||||||
|
last_index = s->block_last_index[n];
|
||||||
|
for(i=1;i<=last_index;i++) {
|
||||||
|
j = s->intra_scantable.permutated[i];
|
||||||
|
val = block[j];
|
||||||
|
if (val == 0) {
|
||||||
|
run++;
|
||||||
|
} else {
|
||||||
|
while (run >= 16) {
|
||||||
|
put_bits(&s->pb, huff_size_ac[0xf0], huff_code_ac[0xf0]);
|
||||||
|
run -= 16;
|
||||||
|
}
|
||||||
|
mant = val;
|
||||||
|
if (val < 0) {
|
||||||
|
val = -val;
|
||||||
|
mant--;
|
||||||
|
}
|
||||||
|
|
||||||
|
nbits= av_log2(val) + 1;
|
||||||
|
code = (run << 4) | nbits;
|
||||||
|
|
||||||
|
put_bits(&s->pb, huff_size_ac[code], huff_code_ac[code]);
|
||||||
|
|
||||||
|
put_sbits(&s->pb, nbits, mant);
|
||||||
|
run = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output EOB only if not already 64 values */
|
||||||
|
if (last_index < 63 || run != 0)
|
||||||
|
put_bits(&s->pb, huff_size_ac[0], huff_code_ac[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ff_mjpeg_encode_mb(MpegEncContext *s, DCTELEM block[6][64])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0;i<5;i++) {
|
||||||
|
encode_block(s, block[i], i);
|
||||||
|
}
|
||||||
|
if (s->chroma_format == CHROMA_420) {
|
||||||
|
encode_block(s, block[5], 5);
|
||||||
|
} else {
|
||||||
|
encode_block(s, block[6], 6);
|
||||||
|
encode_block(s, block[5], 5);
|
||||||
|
encode_block(s, block[7], 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AVCodec mjpeg_encoder = {
|
||||||
|
"mjpeg",
|
||||||
|
CODEC_TYPE_VIDEO,
|
||||||
|
CODEC_ID_MJPEG,
|
||||||
|
sizeof(MpegEncContext),
|
||||||
|
MPV_encode_init,
|
||||||
|
MPV_encode_picture,
|
||||||
|
MPV_encode_end,
|
||||||
|
.pix_fmts= (enum PixelFormat[]){PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_NONE},
|
||||||
|
.long_name= NULL_IF_CONFIG_SMALL("MJPEG (Motion JPEG)"),
|
||||||
|
};
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* MJPEG encoder
|
||||||
|
* Copyright (c) 2000, 2001 Fabrice Bellard.
|
||||||
|
* Copyright (c) 2003 Alex Beregszaszi
|
||||||
|
* Copyright (c) 2003-2004 Michael Niedermayer
|
||||||
|
*
|
||||||
|
* Support for external huffman table, various fixes (AVID workaround),
|
||||||
|
* aspecting, new decode_frame mechanism and apple mjpeg-b support
|
||||||
|
* by Alex Beregszaszi
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mjpegenc.h
|
||||||
|
* MJPEG encoder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FFMPEG_MJPEGENC_H
|
||||||
|
#define FFMPEG_MJPEGENC_H
|
||||||
|
|
||||||
|
#include "dsputil.h"
|
||||||
|
#include "mpegvideo.h"
|
||||||
|
|
||||||
|
typedef struct MJpegContext {
|
||||||
|
uint8_t huff_size_dc_luminance[12]; //FIXME use array [3] instead of lumi / chrom, for easier addressing
|
||||||
|
uint16_t huff_code_dc_luminance[12];
|
||||||
|
uint8_t huff_size_dc_chrominance[12];
|
||||||
|
uint16_t huff_code_dc_chrominance[12];
|
||||||
|
|
||||||
|
uint8_t huff_size_ac_luminance[256];
|
||||||
|
uint16_t huff_code_ac_luminance[256];
|
||||||
|
uint8_t huff_size_ac_chrominance[256];
|
||||||
|
uint16_t huff_code_ac_chrominance[256];
|
||||||
|
} MJpegContext;
|
||||||
|
|
||||||
|
int ff_mjpeg_encode_init(MpegEncContext *s);
|
||||||
|
void ff_mjpeg_encode_close(MpegEncContext *s);
|
||||||
|
void ff_mjpeg_encode_picture_header(MpegEncContext *s);
|
||||||
|
void ff_mjpeg_encode_picture_trailer(MpegEncContext *s);
|
||||||
|
void ff_mjpeg_encode_stuffing(PutBitContext *pbc);
|
||||||
|
void ff_mjpeg_encode_dc(MpegEncContext *s, int val,
|
||||||
|
uint8_t *huff_size, uint16_t *huff_code);
|
||||||
|
void ff_mjpeg_encode_mb(MpegEncContext *s, DCTELEM block[6][64]);
|
||||||
|
|
||||||
|
#endif /* FFMPEG_MJPEGENC_H */
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* MLP codec common code
|
||||||
|
* Copyright (c) 2007-2008 Ian Caulfield
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "libavutil/crc.h"
|
||||||
|
#include "mlp.h"
|
||||||
|
|
||||||
|
const uint8_t ff_mlp_huffman_tables[3][18][2] = {
|
||||||
|
{ /* Huffman table 0, -7 - +10 */
|
||||||
|
{0x01, 9}, {0x01, 8}, {0x01, 7}, {0x01, 6}, {0x01, 5}, {0x01, 4}, {0x01, 3},
|
||||||
|
{0x04, 3}, {0x05, 3}, {0x06, 3}, {0x07, 3},
|
||||||
|
{0x03, 3}, {0x05, 4}, {0x09, 5}, {0x11, 6}, {0x21, 7}, {0x41, 8}, {0x81, 9},
|
||||||
|
}, { /* Huffman table 1, -7 - +8 */
|
||||||
|
{0x01, 9}, {0x01, 8}, {0x01, 7}, {0x01, 6}, {0x01, 5}, {0x01, 4}, {0x01, 3},
|
||||||
|
{0x02, 2}, {0x03, 2},
|
||||||
|
{0x03, 3}, {0x05, 4}, {0x09, 5}, {0x11, 6}, {0x21, 7}, {0x41, 8}, {0x81, 9},
|
||||||
|
}, { /* Huffman table 2, -7 - +7 */
|
||||||
|
{0x01, 9}, {0x01, 8}, {0x01, 7}, {0x01, 6}, {0x01, 5}, {0x01, 4}, {0x01, 3},
|
||||||
|
{0x01, 1},
|
||||||
|
{0x03, 3}, {0x05, 4}, {0x09, 5}, {0x11, 6}, {0x21, 7}, {0x41, 8}, {0x81, 9},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int crc_init = 0;
|
||||||
|
static AVCRC crc_63[1024];
|
||||||
|
static AVCRC crc_1D[1024];
|
||||||
|
|
||||||
|
|
||||||
|
static int crc_init_2D = 0;
|
||||||
|
static AVCRC crc_2D[1024];
|
||||||
|
|
||||||
|
int av_cold ff_mlp_init_crc2D(AVCodecParserContext *s)
|
||||||
|
{
|
||||||
|
if (!crc_init_2D) {
|
||||||
|
av_crc_init(crc_2D, 0, 16, 0x002D, sizeof(crc_2D));
|
||||||
|
crc_init_2D = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void av_cold ff_mlp_init_crc()
|
||||||
|
{
|
||||||
|
if (!crc_init) {
|
||||||
|
av_crc_init(crc_63, 0, 8, 0x63, sizeof(crc_63));
|
||||||
|
av_crc_init(crc_1D, 0, 8, 0x1D, sizeof(crc_1D));
|
||||||
|
crc_init = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ff_mlp_checksum16(const uint8_t *buf, unsigned int buf_size)
|
||||||
|
{
|
||||||
|
uint16_t crc;
|
||||||
|
|
||||||
|
crc = av_crc(crc_2D, 0, buf, buf_size - 2);
|
||||||
|
crc ^= AV_RL16(buf + buf_size - 2);
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ff_mlp_checksum8(const uint8_t *buf, unsigned int buf_size)
|
||||||
|
{
|
||||||
|
uint8_t checksum = av_crc(crc_63, 0x3c, buf, buf_size - 1); // crc_63[0xa2] == 0x3c
|
||||||
|
checksum ^= buf[buf_size-1];
|
||||||
|
return checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ff_mlp_restart_checksum(const uint8_t *buf, unsigned int bit_size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int num_bytes = (bit_size + 2) / 8;
|
||||||
|
|
||||||
|
int crc = crc_1D[buf[0] & 0x3f];
|
||||||
|
crc = av_crc(crc_1D, crc, buf + 1, num_bytes - 2);
|
||||||
|
crc ^= buf[num_bytes - 1];
|
||||||
|
|
||||||
|
for (i = 0; i < ((bit_size + 2) & 7); i++) {
|
||||||
|
crc <<= 1;
|
||||||
|
if (crc & 0x100)
|
||||||
|
crc ^= 0x11D;
|
||||||
|
crc ^= (buf[num_bytes] >> (7 - i)) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ff_mlp_calculate_parity(const uint8_t *buf, unsigned int buf_size)
|
||||||
|
{
|
||||||
|
uint32_t scratch = 0;
|
||||||
|
const uint8_t *buf_end = buf + buf_size;
|
||||||
|
|
||||||
|
for (; buf < buf_end - 3; buf += 4)
|
||||||
|
scratch ^= *((const uint32_t*)buf);
|
||||||
|
|
||||||
|
scratch = xor_32_to_8(scratch);
|
||||||
|
|
||||||
|
for (; buf < buf_end; buf++)
|
||||||
|
scratch ^= *buf;
|
||||||
|
|
||||||
|
return scratch;
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* MLP codec common header file
|
||||||
|
* Copyright (c) 2007-2008 Ian Caulfield
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FFMPEG_MLP_H
|
||||||
|
#define FFMPEG_MLP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
|
||||||
|
/** Maximum number of channels that can be decoded. */
|
||||||
|
#define MAX_CHANNELS 16
|
||||||
|
|
||||||
|
/** Maximum number of matrices used in decoding; most streams have one matrix
|
||||||
|
* per output channel, but some rematrix a channel (usually 0) more than once.
|
||||||
|
*/
|
||||||
|
#define MAX_MATRICES 15
|
||||||
|
|
||||||
|
/** Maximum number of substreams that can be decoded. This could also be set
|
||||||
|
* higher, but I haven't seen any examples with more than two.
|
||||||
|
*/
|
||||||
|
#define MAX_SUBSTREAMS 2
|
||||||
|
|
||||||
|
/** maximum sample frequency seen in files */
|
||||||
|
#define MAX_SAMPLERATE 192000
|
||||||
|
|
||||||
|
/** maximum number of audio samples within one access unit */
|
||||||
|
#define MAX_BLOCKSIZE (40 * (MAX_SAMPLERATE / 48000))
|
||||||
|
/** next power of two greater than MAX_BLOCKSIZE */
|
||||||
|
#define MAX_BLOCKSIZE_POW2 (64 * (MAX_SAMPLERATE / 48000))
|
||||||
|
|
||||||
|
/** number of allowed filters */
|
||||||
|
#define NUM_FILTERS 2
|
||||||
|
|
||||||
|
/** The maximum number of taps in either the IIR or FIR filter;
|
||||||
|
* I believe MLP actually specifies the maximum order for IIR filters as four,
|
||||||
|
* and that the sum of the orders of both filters must be <= 8.
|
||||||
|
*/
|
||||||
|
#define MAX_FILTER_ORDER 8
|
||||||
|
|
||||||
|
/** Code that signals end of a stream. */
|
||||||
|
#define END_OF_STREAM 0xd234d234
|
||||||
|
|
||||||
|
#define FIR 0
|
||||||
|
#define IIR 1
|
||||||
|
|
||||||
|
/** filter data */
|
||||||
|
typedef struct {
|
||||||
|
uint8_t order; ///< number of taps in filter
|
||||||
|
uint8_t shift; ///< Right shift to apply to output of filter.
|
||||||
|
|
||||||
|
int32_t coeff[MAX_FILTER_ORDER];
|
||||||
|
int32_t state[MAX_FILTER_ORDER];
|
||||||
|
} FilterParams;
|
||||||
|
|
||||||
|
/** sample data coding information */
|
||||||
|
typedef struct {
|
||||||
|
FilterParams filter_params[NUM_FILTERS];
|
||||||
|
|
||||||
|
int16_t huff_offset; ///< Offset to apply to residual values.
|
||||||
|
int32_t sign_huff_offset; ///< sign/rounding-corrected version of huff_offset
|
||||||
|
uint8_t codebook; ///< Which VLC codebook to use to read residuals.
|
||||||
|
uint8_t huff_lsbs; ///< Size of residual suffix not encoded using VLC.
|
||||||
|
} ChannelParams;
|
||||||
|
|
||||||
|
/** Tables defining the Huffman codes.
|
||||||
|
* There are three entropy coding methods used in MLP (four if you count
|
||||||
|
* "none" as a method). These use the same sequences for codes starting with
|
||||||
|
* 00 or 01, but have different codes starting with 1.
|
||||||
|
*/
|
||||||
|
extern const uint8_t ff_mlp_huffman_tables[3][18][2];
|
||||||
|
|
||||||
|
/** MLP uses checksums that seem to be based on the standard CRC algorithm, but
|
||||||
|
* are not (in implementation terms, the table lookup and XOR are reversed).
|
||||||
|
* We can implement this behavior using a standard av_crc on all but the
|
||||||
|
* last element, then XOR that with the last element.
|
||||||
|
*/
|
||||||
|
uint8_t ff_mlp_checksum8 (const uint8_t *buf, unsigned int buf_size);
|
||||||
|
uint16_t ff_mlp_checksum16(const uint8_t *buf, unsigned int buf_size);
|
||||||
|
|
||||||
|
/** Calculate an 8-bit checksum over a restart header -- a non-multiple-of-8
|
||||||
|
* number of bits, starting two bits into the first byte of buf.
|
||||||
|
*/
|
||||||
|
uint8_t ff_mlp_restart_checksum(const uint8_t *buf, unsigned int bit_size);
|
||||||
|
|
||||||
|
/** XOR together all the bytes of a buffer.
|
||||||
|
* Does this belong in dspcontext?
|
||||||
|
*/
|
||||||
|
uint8_t ff_mlp_calculate_parity(const uint8_t *buf, unsigned int buf_size);
|
||||||
|
|
||||||
|
int ff_mlp_init_crc2D(AVCodecParserContext *s);
|
||||||
|
|
||||||
|
void ff_mlp_init_crc();
|
||||||
|
|
||||||
|
/** XOR four bytes into one. */
|
||||||
|
static inline uint8_t xor_32_to_8(uint32_t value)
|
||||||
|
{
|
||||||
|
value ^= value >> 16;
|
||||||
|
value ^= value >> 8;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FFMPEG_MLP_H */
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* MLP parser
|
||||||
|
* Copyright (c) 2007 Ian Caulfield
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mlp_parser.c
|
||||||
|
* MLP parser
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "libavutil/crc.h"
|
||||||
|
#include "bitstream.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "mlp_parser.h"
|
||||||
|
#include "mlp.h"
|
||||||
|
|
||||||
|
static const uint8_t mlp_quants[16] = {
|
||||||
|
16, 20, 24, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t mlp_channels[32] = {
|
||||||
|
1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4,
|
||||||
|
5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t thd_chancount[13] = {
|
||||||
|
// LR C LFE LRs LRvh LRc LRrs Cs Ts LRsd LRw Cvh LFE2
|
||||||
|
2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mlp_samplerate(int in)
|
||||||
|
{
|
||||||
|
if (in == 0xF)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (in & 8 ? 44100 : 48000) << (in & 7) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int truehd_channels(int chanmap)
|
||||||
|
{
|
||||||
|
int channels = 0, i;
|
||||||
|
|
||||||
|
for (i = 0; i < 13; i++)
|
||||||
|
channels += thd_chancount[i] * ((chanmap >> i) & 1);
|
||||||
|
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read a major sync info header - contains high level information about
|
||||||
|
* the stream - sample rate, channel arrangement etc. Most of this
|
||||||
|
* information is not actually necessary for decoding, only for playback.
|
||||||
|
* gb must be a freshly initialized GetBitContext with no bits read.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb)
|
||||||
|
{
|
||||||
|
int ratebits;
|
||||||
|
uint16_t checksum;
|
||||||
|
|
||||||
|
assert(get_bits_count(gb) == 0);
|
||||||
|
|
||||||
|
if (gb->size_in_bits < 28 << 3) {
|
||||||
|
av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
checksum = ff_mlp_checksum16(gb->buffer, 26);
|
||||||
|
if (checksum != AV_RL16(gb->buffer+26)) {
|
||||||
|
av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (get_bits_long(gb, 24) != 0xf8726f) /* Sync words */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
mh->stream_type = get_bits(gb, 8);
|
||||||
|
|
||||||
|
if (mh->stream_type == 0xbb) {
|
||||||
|
mh->group1_bits = mlp_quants[get_bits(gb, 4)];
|
||||||
|
mh->group2_bits = mlp_quants[get_bits(gb, 4)];
|
||||||
|
|
||||||
|
ratebits = get_bits(gb, 4);
|
||||||
|
mh->group1_samplerate = mlp_samplerate(ratebits);
|
||||||
|
mh->group2_samplerate = mlp_samplerate(get_bits(gb, 4));
|
||||||
|
|
||||||
|
skip_bits(gb, 11);
|
||||||
|
|
||||||
|
mh->channels_mlp = get_bits(gb, 5);
|
||||||
|
} else if (mh->stream_type == 0xba) {
|
||||||
|
mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere?
|
||||||
|
mh->group2_bits = 0;
|
||||||
|
|
||||||
|
ratebits = get_bits(gb, 4);
|
||||||
|
mh->group1_samplerate = mlp_samplerate(ratebits);
|
||||||
|
mh->group2_samplerate = 0;
|
||||||
|
|
||||||
|
skip_bits(gb, 8);
|
||||||
|
|
||||||
|
mh->channels_thd_stream1 = get_bits(gb, 5);
|
||||||
|
|
||||||
|
skip_bits(gb, 2);
|
||||||
|
|
||||||
|
mh->channels_thd_stream2 = get_bits(gb, 13);
|
||||||
|
} else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
mh->access_unit_size = 40 << (ratebits & 7);
|
||||||
|
mh->access_unit_size_pow2 = 64 << (ratebits & 7);
|
||||||
|
|
||||||
|
skip_bits_long(gb, 48);
|
||||||
|
|
||||||
|
mh->is_vbr = get_bits1(gb);
|
||||||
|
|
||||||
|
mh->peak_bitrate = (get_bits(gb, 15) * mh->group1_samplerate + 8) >> 4;
|
||||||
|
|
||||||
|
mh->num_substreams = get_bits(gb, 4);
|
||||||
|
|
||||||
|
skip_bits_long(gb, 4 + 11 * 8);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct MLPParseContext
|
||||||
|
{
|
||||||
|
ParseContext pc;
|
||||||
|
|
||||||
|
int bytes_left;
|
||||||
|
|
||||||
|
int in_sync;
|
||||||
|
|
||||||
|
int num_substreams;
|
||||||
|
} MLPParseContext;
|
||||||
|
|
||||||
|
static int mlp_parse(AVCodecParserContext *s,
|
||||||
|
AVCodecContext *avctx,
|
||||||
|
const uint8_t **poutbuf, int *poutbuf_size,
|
||||||
|
const uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
MLPParseContext *mp = s->priv_data;
|
||||||
|
int sync_present;
|
||||||
|
uint8_t parity_bits;
|
||||||
|
int next;
|
||||||
|
int i, p = 0;
|
||||||
|
|
||||||
|
*poutbuf_size = 0;
|
||||||
|
if (buf_size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!mp->in_sync) {
|
||||||
|
// Not in sync - find a major sync header
|
||||||
|
|
||||||
|
for (i = 0; i < buf_size; i++) {
|
||||||
|
mp->pc.state = (mp->pc.state << 8) | buf[i];
|
||||||
|
if ((mp->pc.state & 0xfffffffe) == 0xf8726fba) {
|
||||||
|
mp->in_sync = 1;
|
||||||
|
mp->bytes_left = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mp->in_sync) {
|
||||||
|
ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size);
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ff_combine_frame(&mp->pc, i - 7, &buf, &buf_size);
|
||||||
|
|
||||||
|
return i - 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mp->bytes_left == 0) {
|
||||||
|
// Find length of this packet
|
||||||
|
|
||||||
|
/* Copy overread bytes from last frame into buffer. */
|
||||||
|
for(; mp->pc.overread>0; mp->pc.overread--) {
|
||||||
|
mp->pc.buffer[mp->pc.index++]= mp->pc.buffer[mp->pc.overread_index++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mp->pc.index + buf_size < 2) {
|
||||||
|
ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size);
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp->bytes_left = ((mp->pc.index > 0 ? mp->pc.buffer[0] : buf[0]) << 8)
|
||||||
|
| (mp->pc.index > 1 ? mp->pc.buffer[1] : buf[1-mp->pc.index]);
|
||||||
|
mp->bytes_left = (mp->bytes_left & 0xfff) * 2;
|
||||||
|
mp->bytes_left -= mp->pc.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
next = (mp->bytes_left > buf_size) ? END_NOT_FOUND : mp->bytes_left;
|
||||||
|
|
||||||
|
if (ff_combine_frame(&mp->pc, next, &buf, &buf_size) < 0) {
|
||||||
|
mp->bytes_left -= buf_size;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp->bytes_left = 0;
|
||||||
|
|
||||||
|
sync_present = (AV_RB32(buf + 4) & 0xfffffffe) == 0xf8726fba;
|
||||||
|
|
||||||
|
if (!sync_present) {
|
||||||
|
/* The first nibble of a frame is a parity check of the 4-byte
|
||||||
|
* access unit header and all the 2- or 4-byte substream headers. */
|
||||||
|
// Only check when this isn't a sync frame - syncs have a checksum.
|
||||||
|
|
||||||
|
parity_bits = 0;
|
||||||
|
for (i = -1; i < mp->num_substreams; i++) {
|
||||||
|
parity_bits ^= buf[p++];
|
||||||
|
parity_bits ^= buf[p++];
|
||||||
|
|
||||||
|
if (i < 0 || buf[p-2] & 0x80) {
|
||||||
|
parity_bits ^= buf[p++];
|
||||||
|
parity_bits ^= buf[p++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((((parity_bits >> 4) ^ parity_bits) & 0xF) != 0xF) {
|
||||||
|
av_log(avctx, AV_LOG_INFO, "mlpparse: Parity check failed.\n");
|
||||||
|
goto lost_sync;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
GetBitContext gb;
|
||||||
|
MLPHeaderInfo mh;
|
||||||
|
|
||||||
|
init_get_bits(&gb, buf + 4, (buf_size - 4) << 3);
|
||||||
|
if (ff_mlp_read_major_sync(avctx, &mh, &gb) < 0)
|
||||||
|
goto lost_sync;
|
||||||
|
|
||||||
|
#ifdef CONFIG_AUDIO_NONSHORT
|
||||||
|
avctx->bits_per_sample = mh.group1_bits;
|
||||||
|
if (avctx->bits_per_sample > 16)
|
||||||
|
avctx->sample_fmt = SAMPLE_FMT_S32;
|
||||||
|
#endif
|
||||||
|
avctx->sample_rate = mh.group1_samplerate;
|
||||||
|
avctx->frame_size = mh.access_unit_size;
|
||||||
|
|
||||||
|
if (mh.stream_type == 0xbb) {
|
||||||
|
/* MLP stream */
|
||||||
|
avctx->channels = mlp_channels[mh.channels_mlp];
|
||||||
|
} else { /* mh.stream_type == 0xba */
|
||||||
|
/* TrueHD stream */
|
||||||
|
if (mh.channels_thd_stream2)
|
||||||
|
avctx->channels = truehd_channels(mh.channels_thd_stream2);
|
||||||
|
else
|
||||||
|
avctx->channels = truehd_channels(mh.channels_thd_stream1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mh.is_vbr) /* Stream is CBR */
|
||||||
|
avctx->bit_rate = mh.peak_bitrate;
|
||||||
|
|
||||||
|
mp->num_substreams = mh.num_substreams;
|
||||||
|
}
|
||||||
|
|
||||||
|
*poutbuf = buf;
|
||||||
|
*poutbuf_size = buf_size;
|
||||||
|
|
||||||
|
return next;
|
||||||
|
|
||||||
|
lost_sync:
|
||||||
|
mp->in_sync = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVCodecParser mlp_parser = {
|
||||||
|
{ CODEC_ID_MLP },
|
||||||
|
sizeof(MLPParseContext),
|
||||||
|
ff_mlp_init_crc2D,
|
||||||
|
mlp_parse,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* MLP parser prototypes
|
||||||
|
* Copyright (c) 2007 Ian Caulfield
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mlp_parser.h
|
||||||
|
* MLP parser prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FFMPEG_MLP_PARSER_H
|
||||||
|
#define FFMPEG_MLP_PARSER_H
|
||||||
|
|
||||||
|
#include "bitstream.h"
|
||||||
|
|
||||||
|
typedef struct MLPHeaderInfo
|
||||||
|
{
|
||||||
|
int stream_type; ///< 0xBB for MLP, 0xBA for TrueHD
|
||||||
|
|
||||||
|
int group1_bits; ///< The bit depth of the first substream
|
||||||
|
int group2_bits; ///< Bit depth of the second substream (MLP only)
|
||||||
|
|
||||||
|
int group1_samplerate; ///< Sample rate of first substream
|
||||||
|
int group2_samplerate; ///< Sample rate of second substream (MLP only)
|
||||||
|
|
||||||
|
int channels_mlp; ///< Channel arrangement for MLP streams
|
||||||
|
int channels_thd_stream1; ///< Channel arrangement for substream 1 of TrueHD streams (5.1)
|
||||||
|
int channels_thd_stream2; ///< Channel arrangement for substream 2 of TrueHD streams (7.1)
|
||||||
|
|
||||||
|
int access_unit_size; ///< Number of samples per coded frame
|
||||||
|
int access_unit_size_pow2; ///< Next power of two above number of samples per frame
|
||||||
|
|
||||||
|
int is_vbr; ///< Stream is VBR instead of CBR
|
||||||
|
int peak_bitrate; ///< Peak bitrate for VBR, actual bitrate (==peak) for CBR
|
||||||
|
|
||||||
|
int num_substreams; ///< Number of substreams within stream
|
||||||
|
} MLPHeaderInfo;
|
||||||
|
|
||||||
|
|
||||||
|
int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb);
|
||||||
|
|
||||||
|
#endif /* FFMPEG_MLP_PARSER_H */
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* American Laser Games MM Video Decoder
|
||||||
|
* Copyright (c) 2006,2008 Peter Ross
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mm.c
|
||||||
|
* American Laser Games MM Video Decoder
|
||||||
|
* by Peter Ross (suxen_drol at hotmail dot com)
|
||||||
|
*
|
||||||
|
* The MM format was used by IBM-PC ports of ALG's "arcade shooter" games,
|
||||||
|
* including Mad Dog McCree and Crime Patrol.
|
||||||
|
*
|
||||||
|
* Technical details here:
|
||||||
|
* http://wiki.multimedia.cx/index.php?title=American_Laser_Games_MM
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
|
||||||
|
#define MM_PREAMBLE_SIZE 6
|
||||||
|
|
||||||
|
#define MM_TYPE_INTER 0x5
|
||||||
|
#define MM_TYPE_INTRA 0x8
|
||||||
|
#define MM_TYPE_INTRA_HH 0xc
|
||||||
|
#define MM_TYPE_INTER_HH 0xd
|
||||||
|
#define MM_TYPE_INTRA_HHV 0xe
|
||||||
|
#define MM_TYPE_INTER_HHV 0xf
|
||||||
|
#define MM_TYPE_PALETTE 0x31
|
||||||
|
|
||||||
|
typedef struct MmContext {
|
||||||
|
AVCodecContext *avctx;
|
||||||
|
AVFrame frame;
|
||||||
|
int palette[AVPALETTE_COUNT];
|
||||||
|
} MmContext;
|
||||||
|
|
||||||
|
static av_cold int mm_decode_init(AVCodecContext *avctx)
|
||||||
|
{
|
||||||
|
MmContext *s = avctx->priv_data;
|
||||||
|
|
||||||
|
s->avctx = avctx;
|
||||||
|
|
||||||
|
avctx->pix_fmt = PIX_FMT_PAL8;
|
||||||
|
|
||||||
|
if (avcodec_check_dimensions(avctx, avctx->width, avctx->height))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
s->frame.reference = 1;
|
||||||
|
if (avctx->get_buffer(avctx, &s->frame)) {
|
||||||
|
av_log(s->avctx, AV_LOG_ERROR, "mmvideo: get_buffer() failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mm_decode_pal(MmContext *s, const uint8_t *buf, const uint8_t *buf_end)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
buf += 4;
|
||||||
|
for (i=0; i<128 && buf+2<buf_end; i++) {
|
||||||
|
s->palette[i] = AV_RB24(buf);
|
||||||
|
s->palette[i+128] = s->palette[i]<<2;
|
||||||
|
buf += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mm_decode_intra(MmContext * s, int half_horiz, int half_vert, const uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
int i, x, y;
|
||||||
|
i=0; x=0; y=0;
|
||||||
|
|
||||||
|
while(i<buf_size) {
|
||||||
|
int run_length, color;
|
||||||
|
|
||||||
|
if (buf[i] & 0x80) {
|
||||||
|
run_length = 1;
|
||||||
|
color = buf[i];
|
||||||
|
i++;
|
||||||
|
}else{
|
||||||
|
run_length = (buf[i] & 0x7f) + 2;
|
||||||
|
color = buf[i+1];
|
||||||
|
i+=2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (half_horiz)
|
||||||
|
run_length *=2;
|
||||||
|
|
||||||
|
if (color) {
|
||||||
|
memset(s->frame.data[0] + y*s->frame.linesize[0] + x, color, run_length);
|
||||||
|
if (half_vert)
|
||||||
|
memset(s->frame.data[0] + (y+1)*s->frame.linesize[0] + x, color, run_length);
|
||||||
|
}
|
||||||
|
x+= run_length;
|
||||||
|
|
||||||
|
if (x >= s->avctx->width) {
|
||||||
|
x=0;
|
||||||
|
y += half_vert ? 2 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mm_decode_inter(MmContext * s, int half_horiz, int half_vert, const uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
const int data_ptr = 2 + AV_RL16(&buf[0]);
|
||||||
|
int d, r, y;
|
||||||
|
d = data_ptr; r = 2; y = 0;
|
||||||
|
|
||||||
|
while(r < data_ptr) {
|
||||||
|
int i, j;
|
||||||
|
int length = buf[r] & 0x7f;
|
||||||
|
int x = buf[r+1] + ((buf[r] & 0x80) << 1);
|
||||||
|
r += 2;
|
||||||
|
|
||||||
|
if (length==0) {
|
||||||
|
y += x;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; i<length; i++) {
|
||||||
|
for(j=0; j<8; j++) {
|
||||||
|
int replace = (buf[r+i] >> (7-j)) & 1;
|
||||||
|
if (replace) {
|
||||||
|
int color = buf[d];
|
||||||
|
s->frame.data[0][y*s->frame.linesize[0] + x] = color;
|
||||||
|
if (half_horiz)
|
||||||
|
s->frame.data[0][y*s->frame.linesize[0] + x + 1] = color;
|
||||||
|
if (half_vert) {
|
||||||
|
s->frame.data[0][(y+1)*s->frame.linesize[0] + x] = color;
|
||||||
|
if (half_horiz)
|
||||||
|
s->frame.data[0][(y+1)*s->frame.linesize[0] + x + 1] = color;
|
||||||
|
}
|
||||||
|
d++;
|
||||||
|
}
|
||||||
|
x += half_horiz ? 2 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r += length;
|
||||||
|
y += half_vert ? 2 : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mm_decode_frame(AVCodecContext *avctx,
|
||||||
|
void *data, int *data_size,
|
||||||
|
const uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
MmContext *s = avctx->priv_data;
|
||||||
|
const uint8_t *buf_end = buf+buf_size;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
type = AV_RL16(&buf[0]);
|
||||||
|
buf += MM_PREAMBLE_SIZE;
|
||||||
|
buf_size -= MM_PREAMBLE_SIZE;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case MM_TYPE_PALETTE : mm_decode_pal(s, buf, buf_end); return buf_size;
|
||||||
|
case MM_TYPE_INTRA : mm_decode_intra(s, 0, 0, buf, buf_size); break;
|
||||||
|
case MM_TYPE_INTRA_HH : mm_decode_intra(s, 1, 0, buf, buf_size); break;
|
||||||
|
case MM_TYPE_INTRA_HHV : mm_decode_intra(s, 1, 1, buf, buf_size); break;
|
||||||
|
case MM_TYPE_INTER : mm_decode_inter(s, 0, 0, buf, buf_size); break;
|
||||||
|
case MM_TYPE_INTER_HH : mm_decode_inter(s, 1, 0, buf, buf_size); break;
|
||||||
|
case MM_TYPE_INTER_HHV : mm_decode_inter(s, 1, 1, buf, buf_size); break;
|
||||||
|
default :
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
|
||||||
|
|
||||||
|
*data_size = sizeof(AVFrame);
|
||||||
|
*(AVFrame*)data = s->frame;
|
||||||
|
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_cold int mm_decode_end(AVCodecContext *avctx)
|
||||||
|
{
|
||||||
|
MmContext *s = avctx->priv_data;
|
||||||
|
|
||||||
|
if(s->frame.data[0])
|
||||||
|
avctx->release_buffer(avctx, &s->frame);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVCodec mmvideo_decoder = {
|
||||||
|
"mmvideo",
|
||||||
|
CODEC_TYPE_VIDEO,
|
||||||
|
CODEC_ID_MMVIDEO,
|
||||||
|
sizeof(MmContext),
|
||||||
|
mm_decode_init,
|
||||||
|
NULL,
|
||||||
|
mm_decode_end,
|
||||||
|
mm_decode_frame,
|
||||||
|
CODEC_CAP_DR1,
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("American Laser Games MM Video"),
|
||||||
|
};
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* (c) 2001 Fabrice Bellard
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file motion_test.c
|
||||||
|
* motion test.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "dsputil.h"
|
||||||
|
|
||||||
|
#include "i386/mmx.h"
|
||||||
|
|
||||||
|
#undef exit
|
||||||
|
#undef printf
|
||||||
|
#undef random
|
||||||
|
|
||||||
|
#define WIDTH 64
|
||||||
|
#define HEIGHT 64
|
||||||
|
|
||||||
|
uint8_t img1[WIDTH * HEIGHT];
|
||||||
|
uint8_t img2[WIDTH * HEIGHT];
|
||||||
|
|
||||||
|
void fill_random(uint8_t *tab, int size)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0;i<size;i++) {
|
||||||
|
#if 1
|
||||||
|
tab[i] = random() % 256;
|
||||||
|
#else
|
||||||
|
tab[i] = i;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void help(void)
|
||||||
|
{
|
||||||
|
printf("motion-test [-h]\n"
|
||||||
|
"test motion implementations\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t gettime(void)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv,NULL);
|
||||||
|
return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NB_ITS 500
|
||||||
|
|
||||||
|
int dummy;
|
||||||
|
|
||||||
|
void test_motion(const char *name,
|
||||||
|
me_cmp_func test_func, me_cmp_func ref_func)
|
||||||
|
{
|
||||||
|
int x, y, d1, d2, it;
|
||||||
|
uint8_t *ptr;
|
||||||
|
int64_t ti;
|
||||||
|
printf("testing '%s'\n", name);
|
||||||
|
|
||||||
|
/* test correctness */
|
||||||
|
for(it=0;it<20;it++) {
|
||||||
|
|
||||||
|
fill_random(img1, WIDTH * HEIGHT);
|
||||||
|
fill_random(img2, WIDTH * HEIGHT);
|
||||||
|
|
||||||
|
for(y=0;y<HEIGHT-17;y++) {
|
||||||
|
for(x=0;x<WIDTH-17;x++) {
|
||||||
|
ptr = img2 + y * WIDTH + x;
|
||||||
|
d1 = test_func(NULL, img1, ptr, WIDTH, 1);
|
||||||
|
d2 = ref_func(NULL, img1, ptr, WIDTH, 1);
|
||||||
|
if (d1 != d2) {
|
||||||
|
printf("error: mmx=%d c=%d\n", d1, d2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emms_c();
|
||||||
|
|
||||||
|
/* speed test */
|
||||||
|
ti = gettime();
|
||||||
|
d1 = 0;
|
||||||
|
for(it=0;it<NB_ITS;it++) {
|
||||||
|
for(y=0;y<HEIGHT-17;y++) {
|
||||||
|
for(x=0;x<WIDTH-17;x++) {
|
||||||
|
ptr = img2 + y * WIDTH + x;
|
||||||
|
d1 += test_func(NULL, img1, ptr, WIDTH, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emms_c();
|
||||||
|
dummy = d1; /* avoid optimization */
|
||||||
|
ti = gettime() - ti;
|
||||||
|
|
||||||
|
printf(" %0.0f kop/s\n",
|
||||||
|
(double)NB_ITS * (WIDTH - 16) * (HEIGHT - 16) /
|
||||||
|
(double)(ti / 1000.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
AVCodecContext *ctx;
|
||||||
|
int c;
|
||||||
|
DSPContext cctx, mmxctx;
|
||||||
|
int flags[2] = { FF_MM_MMX, FF_MM_MMXEXT };
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
c = getopt(argc, argv, "h");
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
switch(c) {
|
||||||
|
case 'h':
|
||||||
|
help();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("ffmpeg motion test\n");
|
||||||
|
|
||||||
|
ctx = avcodec_alloc_context();
|
||||||
|
ctx->dsp_mask = FF_MM_FORCE;
|
||||||
|
dsputil_init(&cctx, ctx);
|
||||||
|
for (c = 0; c < 2; c++) {
|
||||||
|
int x;
|
||||||
|
ctx->dsp_mask = FF_MM_FORCE | flags[c];
|
||||||
|
dsputil_init(&mmxctx, ctx);
|
||||||
|
|
||||||
|
for (x = 0; x < 2; x++) {
|
||||||
|
printf("%s for %dx%d pixels\n", c ? "mmx2" : "mmx",
|
||||||
|
x ? 8 : 16, x ? 8 : 16);
|
||||||
|
test_motion("mmx", mmxctx.pix_abs[x][0], cctx.pix_abs[x][0]);
|
||||||
|
test_motion("mmx_x2", mmxctx.pix_abs[x][1], cctx.pix_abs[x][1]);
|
||||||
|
test_motion("mmx_y2", mmxctx.pix_abs[x][2], cctx.pix_abs[x][2]);
|
||||||
|
test_motion("mmx_xy2", mmxctx.pix_abs[x][3], cctx.pix_abs[x][3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
av_free(ctx);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,363 @@
|
|||||||
|
/*
|
||||||
|
* Motion Pixels Video Decoder
|
||||||
|
* Copyright (c) 2008 Gregory Montoir (cyx@users.sourceforge.net)
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "bitstream.h"
|
||||||
|
#include "dsputil.h"
|
||||||
|
|
||||||
|
#define MAX_HUFF_CODES 16
|
||||||
|
|
||||||
|
typedef struct YuvPixel {
|
||||||
|
int8_t y, v, u;
|
||||||
|
} YuvPixel;
|
||||||
|
|
||||||
|
typedef struct HuffCode {
|
||||||
|
int code;
|
||||||
|
uint8_t size;
|
||||||
|
uint8_t delta;
|
||||||
|
} HuffCode;
|
||||||
|
|
||||||
|
typedef struct MotionPixelsContext {
|
||||||
|
AVCodecContext *avctx;
|
||||||
|
AVFrame frame;
|
||||||
|
DSPContext dsp;
|
||||||
|
uint8_t *changes_map;
|
||||||
|
int offset_bits_len;
|
||||||
|
int codes_count, current_codes_count;
|
||||||
|
int max_codes_bits;
|
||||||
|
HuffCode codes[MAX_HUFF_CODES];
|
||||||
|
VLC vlc;
|
||||||
|
YuvPixel *vpt, *hpt;
|
||||||
|
uint8_t gradient_scale[3];
|
||||||
|
uint8_t *bswapbuf;
|
||||||
|
int bswapbuf_size;
|
||||||
|
} MotionPixelsContext;
|
||||||
|
|
||||||
|
static YuvPixel mp_rgb_yuv_table[1 << 15];
|
||||||
|
|
||||||
|
static int mp_yuv_to_rgb(int y, int v, int u, int clip_rgb) {
|
||||||
|
static const uint8_t *cm = ff_cropTbl + MAX_NEG_CROP;
|
||||||
|
int r, g, b;
|
||||||
|
|
||||||
|
r = (1000 * y + 701 * v) / 1000;
|
||||||
|
g = (1000 * y - 357 * v - 172 * u) / 1000;
|
||||||
|
b = (1000 * y + 886 * u) / 1000;
|
||||||
|
if (clip_rgb)
|
||||||
|
return ((cm[r * 8] & 0xF8) << 7) | ((cm[g * 8] & 0xF8) << 2) | (cm[b * 8] >> 3);
|
||||||
|
if ((unsigned)r < 32 && (unsigned)g < 32 && (unsigned)b < 32)
|
||||||
|
return (r << 10) | (g << 5) | b;
|
||||||
|
return 1 << 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_set_zero_yuv(YuvPixel *p)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < 31; ++i) {
|
||||||
|
for (j = 31; j > i; --j)
|
||||||
|
if (!(p[j].u | p[j].v | p[j].y))
|
||||||
|
p[j] = p[j - 1];
|
||||||
|
for (j = 0; j < 31 - i; ++j)
|
||||||
|
if (!(p[j].u | p[j].v | p[j].y))
|
||||||
|
p[j] = p[j + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_build_rgb_yuv_table(YuvPixel *p)
|
||||||
|
{
|
||||||
|
int y, v, u, i;
|
||||||
|
|
||||||
|
for (y = 0; y <= 31; ++y)
|
||||||
|
for (v = -31; v <= 31; ++v)
|
||||||
|
for (u = -31; u <= 31; ++u) {
|
||||||
|
i = mp_yuv_to_rgb(y, v, u, 0);
|
||||||
|
if (i < (1 << 15) && !(p[i].u | p[i].v | p[i].y)) {
|
||||||
|
p[i].y = y;
|
||||||
|
p[i].v = v;
|
||||||
|
p[i].u = u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < 1024; ++i)
|
||||||
|
mp_set_zero_yuv(p + i * 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_cold int mp_decode_init(AVCodecContext *avctx)
|
||||||
|
{
|
||||||
|
MotionPixelsContext *mp = avctx->priv_data;
|
||||||
|
|
||||||
|
if (!mp_rgb_yuv_table[0].u) {
|
||||||
|
mp_build_rgb_yuv_table(mp_rgb_yuv_table);
|
||||||
|
}
|
||||||
|
mp->avctx = avctx;
|
||||||
|
dsputil_init(&mp->dsp, avctx);
|
||||||
|
mp->changes_map = av_mallocz(avctx->width * avctx->height);
|
||||||
|
mp->offset_bits_len = av_log2(avctx->width * avctx->height) + 1;
|
||||||
|
mp->vpt = av_mallocz(avctx->height * sizeof(YuvPixel));
|
||||||
|
mp->hpt = av_mallocz(avctx->height * avctx->width / 16 * sizeof(YuvPixel));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_read_changes_map(MotionPixelsContext *mp, GetBitContext *gb, int count, int bits_len, int read_color)
|
||||||
|
{
|
||||||
|
uint16_t *pixels;
|
||||||
|
int offset, w, h, color = 0, x, y, i;
|
||||||
|
|
||||||
|
while (count--) {
|
||||||
|
offset = get_bits_long(gb, mp->offset_bits_len);
|
||||||
|
w = get_bits(gb, bits_len) + 1;
|
||||||
|
h = get_bits(gb, bits_len) + 1;
|
||||||
|
if (read_color)
|
||||||
|
color = get_bits(gb, 15);
|
||||||
|
x = offset % mp->avctx->width;
|
||||||
|
y = offset / mp->avctx->width;
|
||||||
|
if (y >= mp->avctx->height)
|
||||||
|
continue;
|
||||||
|
w = FFMIN(w, mp->avctx->width - x);
|
||||||
|
h = FFMIN(h, mp->avctx->height - y);
|
||||||
|
pixels = (uint16_t *)&mp->frame.data[0][y * mp->frame.linesize[0] + x * 2];
|
||||||
|
while (h--) {
|
||||||
|
mp->changes_map[offset] = w;
|
||||||
|
if (read_color)
|
||||||
|
for (i = 0; i < w; ++i)
|
||||||
|
pixels[i] = color;
|
||||||
|
offset += mp->avctx->width;
|
||||||
|
pixels += mp->frame.linesize[0] / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_get_code(MotionPixelsContext *mp, GetBitContext *gb, int size, int code)
|
||||||
|
{
|
||||||
|
while (get_bits1(gb)) {
|
||||||
|
++size;
|
||||||
|
if (size > mp->max_codes_bits) {
|
||||||
|
av_log(mp->avctx, AV_LOG_ERROR, "invalid code size %d/%d\n", size, mp->max_codes_bits);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
code <<= 1;
|
||||||
|
mp_get_code(mp, gb, size, code + 1);
|
||||||
|
}
|
||||||
|
if (mp->current_codes_count >= MAX_HUFF_CODES) {
|
||||||
|
av_log(mp->avctx, AV_LOG_ERROR, "too many codes\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mp->codes[mp->current_codes_count ].code = code;
|
||||||
|
mp->codes[mp->current_codes_count++].size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_read_codes_table(MotionPixelsContext *mp, GetBitContext *gb)
|
||||||
|
{
|
||||||
|
if (mp->codes_count == 1) {
|
||||||
|
mp->codes[0].delta = get_bits(gb, 4);
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
mp->max_codes_bits = get_bits(gb, 4);
|
||||||
|
for (i = 0; i < mp->codes_count; ++i)
|
||||||
|
mp->codes[i].delta = get_bits(gb, 4);
|
||||||
|
mp->current_codes_count = 0;
|
||||||
|
mp_get_code(mp, gb, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mp_gradient(MotionPixelsContext *mp, int component, int v)
|
||||||
|
{
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
delta = (v - 7) * mp->gradient_scale[component];
|
||||||
|
mp->gradient_scale[component] = (v == 0 || v == 14) ? 2 : 1;
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
static YuvPixel mp_get_yuv_from_rgb(MotionPixelsContext *mp, int x, int y)
|
||||||
|
{
|
||||||
|
int color;
|
||||||
|
|
||||||
|
color = *(uint16_t *)&mp->frame.data[0][y * mp->frame.linesize[0] + x * 2];
|
||||||
|
return mp_rgb_yuv_table[color];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_set_rgb_from_yuv(MotionPixelsContext *mp, int x, int y, const YuvPixel *p)
|
||||||
|
{
|
||||||
|
int color;
|
||||||
|
|
||||||
|
color = mp_yuv_to_rgb(p->y, p->v, p->u, 1);
|
||||||
|
*(uint16_t *)&mp->frame.data[0][y * mp->frame.linesize[0] + x * 2] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = (mp->codes_count == 1) ? 0 : get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1);
|
||||||
|
return mp->codes[i].delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_decode_line(MotionPixelsContext *mp, GetBitContext *gb, int y)
|
||||||
|
{
|
||||||
|
YuvPixel p;
|
||||||
|
const int y0 = y * mp->avctx->width;
|
||||||
|
int w, i, x = 0;
|
||||||
|
|
||||||
|
p = mp->vpt[y];
|
||||||
|
if (mp->changes_map[y0 + x] == 0) {
|
||||||
|
memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
|
||||||
|
++x;
|
||||||
|
}
|
||||||
|
while (x < mp->avctx->width) {
|
||||||
|
w = mp->changes_map[y0 + x];
|
||||||
|
if (w != 0) {
|
||||||
|
if ((y & 3) == 0) {
|
||||||
|
if (mp->changes_map[y0 + x + mp->avctx->width] < w ||
|
||||||
|
mp->changes_map[y0 + x + mp->avctx->width * 2] < w ||
|
||||||
|
mp->changes_map[y0 + x + mp->avctx->width * 3] < w) {
|
||||||
|
for (i = (x + 3) & ~3; i < x + w; i += 4) {
|
||||||
|
mp->hpt[((y / 4) * mp->avctx->width + i) / 4] = mp_get_yuv_from_rgb(mp, i, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x += w;
|
||||||
|
memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
|
||||||
|
p = mp_get_yuv_from_rgb(mp, x - 1, y);
|
||||||
|
} else {
|
||||||
|
p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
|
||||||
|
if ((x & 3) == 0) {
|
||||||
|
if ((y & 3) == 0) {
|
||||||
|
p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
|
||||||
|
p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
|
||||||
|
mp->hpt[((y / 4) * mp->avctx->width + x) / 4] = p;
|
||||||
|
} else {
|
||||||
|
p.v = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].v;
|
||||||
|
p.u = mp->hpt[((y / 4) * mp->avctx->width + x) / 4].u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mp_set_rgb_from_yuv(mp, x, y, &p);
|
||||||
|
++x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mp_decode_frame_helper(MotionPixelsContext *mp, GetBitContext *gb)
|
||||||
|
{
|
||||||
|
YuvPixel p;
|
||||||
|
int y, y0;
|
||||||
|
|
||||||
|
for (y = 0; y < mp->avctx->height; ++y) {
|
||||||
|
if (mp->changes_map[y * mp->avctx->width] != 0) {
|
||||||
|
memset(mp->gradient_scale, 1, sizeof(mp->gradient_scale));
|
||||||
|
p = mp_get_yuv_from_rgb(mp, 0, y);
|
||||||
|
} else {
|
||||||
|
p.y += mp_gradient(mp, 0, mp_get_vlc(mp, gb));
|
||||||
|
if ((y & 3) == 0) {
|
||||||
|
p.v += mp_gradient(mp, 1, mp_get_vlc(mp, gb));
|
||||||
|
p.u += mp_gradient(mp, 2, mp_get_vlc(mp, gb));
|
||||||
|
}
|
||||||
|
mp->vpt[y] = p;
|
||||||
|
mp_set_rgb_from_yuv(mp, 0, y, &p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (y0 = 0; y0 < 2; ++y0)
|
||||||
|
for (y = y0; y < mp->avctx->height; y += 2)
|
||||||
|
mp_decode_line(mp, gb, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mp_decode_frame(AVCodecContext *avctx,
|
||||||
|
void *data, int *data_size,
|
||||||
|
const uint8_t *buf, int buf_size)
|
||||||
|
{
|
||||||
|
MotionPixelsContext *mp = avctx->priv_data;
|
||||||
|
GetBitContext gb;
|
||||||
|
int i, count1, count2, sz;
|
||||||
|
|
||||||
|
mp->frame.reference = 1;
|
||||||
|
mp->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE;
|
||||||
|
if (avctx->reget_buffer(avctx, &mp->frame)) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* le32 bitstream msb first */
|
||||||
|
mp->bswapbuf = av_fast_realloc(mp->bswapbuf, &mp->bswapbuf_size, buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
mp->dsp.bswap_buf((uint32_t *)mp->bswapbuf, (const uint32_t *)buf, buf_size / 4);
|
||||||
|
if (buf_size & 3)
|
||||||
|
memcpy(mp->bswapbuf + (buf_size & ~3), buf + (buf_size & ~3), buf_size & 3);
|
||||||
|
init_get_bits(&gb, mp->bswapbuf, buf_size * 8);
|
||||||
|
|
||||||
|
memset(mp->changes_map, 0, avctx->width * avctx->height);
|
||||||
|
for (i = !(avctx->extradata[1] & 2); i < 2; ++i) {
|
||||||
|
count1 = get_bits(&gb, 12);
|
||||||
|
count2 = get_bits(&gb, 12);
|
||||||
|
mp_read_changes_map(mp, &gb, count1, 8, i);
|
||||||
|
mp_read_changes_map(mp, &gb, count2, 4, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
mp->codes_count = get_bits(&gb, 4);
|
||||||
|
if (mp->codes_count == 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (mp->changes_map[0] == 0) {
|
||||||
|
*(uint16_t *)mp->frame.data[0] = get_bits(&gb, 15);
|
||||||
|
mp->changes_map[0] = 1;
|
||||||
|
}
|
||||||
|
mp_read_codes_table(mp, &gb);
|
||||||
|
|
||||||
|
sz = get_bits(&gb, 18);
|
||||||
|
if (avctx->extradata[0] != 5)
|
||||||
|
sz += get_bits(&gb, 18);
|
||||||
|
if (sz == 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
init_vlc(&mp->vlc, mp->max_codes_bits, mp->codes_count, &mp->codes[0].size, sizeof(HuffCode), 1, &mp->codes[0].code, sizeof(HuffCode), 4, 0);
|
||||||
|
mp_decode_frame_helper(mp, &gb);
|
||||||
|
free_vlc(&mp->vlc);
|
||||||
|
|
||||||
|
end:
|
||||||
|
*data_size = sizeof(AVFrame);
|
||||||
|
*(AVFrame *)data = mp->frame;
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static av_cold int mp_decode_end(AVCodecContext *avctx)
|
||||||
|
{
|
||||||
|
MotionPixelsContext *mp = avctx->priv_data;
|
||||||
|
|
||||||
|
av_freep(&mp->changes_map);
|
||||||
|
av_freep(&mp->vpt);
|
||||||
|
av_freep(&mp->hpt);
|
||||||
|
av_freep(&mp->bswapbuf);
|
||||||
|
if (mp->frame.data[0])
|
||||||
|
avctx->release_buffer(avctx, &mp->frame);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVCodec motionpixels_decoder = {
|
||||||
|
"motionpixels",
|
||||||
|
CODEC_TYPE_VIDEO,
|
||||||
|
CODEC_ID_MOTIONPIXELS,
|
||||||
|
sizeof(MotionPixelsContext),
|
||||||
|
mp_decode_init,
|
||||||
|
NULL,
|
||||||
|
mp_decode_end,
|
||||||
|
mp_decode_frame,
|
||||||
|
CODEC_CAP_DR1,
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("Motion Pixels Video"),
|
||||||
|
};
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2008 Reimar Döffinger
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int text2movsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
|
||||||
|
uint8_t **poutbuf, int *poutbuf_size,
|
||||||
|
const uint8_t *buf, int buf_size, int keyframe){
|
||||||
|
if (buf_size > 0xffff) return 0;
|
||||||
|
*poutbuf_size = buf_size + 2;
|
||||||
|
*poutbuf = av_malloc(*poutbuf_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
AV_WB16(*poutbuf, buf_size);
|
||||||
|
memcpy(*poutbuf + 2, buf, buf_size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVBitStreamFilter text2movsub_bsf={
|
||||||
|
"text2movsub",
|
||||||
|
0,
|
||||||
|
text2movsub,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mov2textsub(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
|
||||||
|
uint8_t **poutbuf, int *poutbuf_size,
|
||||||
|
const uint8_t *buf, int buf_size, int keyframe){
|
||||||
|
if (buf_size < 2) return 0;
|
||||||
|
*poutbuf_size = FFMIN(buf_size - 2, AV_RB16(buf));
|
||||||
|
*poutbuf = av_malloc(*poutbuf_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
memcpy(*poutbuf, buf + 2, *poutbuf_size);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVBitStreamFilter mov2textsub_bsf={
|
||||||
|
"mov2textsub",
|
||||||
|
0,
|
||||||
|
mov2textsub,
|
||||||
|
};
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "mpegaudio.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int mp3_header_compress(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
|
||||||
|
uint8_t **poutbuf, int *poutbuf_size,
|
||||||
|
const uint8_t *buf, int buf_size, int keyframe){
|
||||||
|
uint32_t header, extraheader;
|
||||||
|
int mode_extension, header_size;
|
||||||
|
|
||||||
|
if(avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL){
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "not standards compliant\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = AV_RB32(buf);
|
||||||
|
mode_extension= (header>>4)&3;
|
||||||
|
|
||||||
|
if(ff_mpa_check_header(header) < 0 || (header&0x60000) != 0x20000){
|
||||||
|
output_unchanged:
|
||||||
|
*poutbuf= (uint8_t *) buf;
|
||||||
|
*poutbuf_size= buf_size;
|
||||||
|
|
||||||
|
av_log(avctx, AV_LOG_INFO, "cannot compress %08X\n", header);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(avctx->extradata_size == 0){
|
||||||
|
avctx->extradata_size=15;
|
||||||
|
avctx->extradata= av_malloc(avctx->extradata_size);
|
||||||
|
strcpy(avctx->extradata, "FFCMP3 0.0");
|
||||||
|
memcpy(avctx->extradata+11, buf, 4);
|
||||||
|
}
|
||||||
|
if(avctx->extradata_size != 15){
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Extradata invalid\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
extraheader = AV_RB32(avctx->extradata+11);
|
||||||
|
if((extraheader&MP3_MASK) != (header&MP3_MASK))
|
||||||
|
goto output_unchanged;
|
||||||
|
|
||||||
|
header_size= (header&0x10000) ? 4 : 6;
|
||||||
|
|
||||||
|
*poutbuf_size= buf_size - header_size;
|
||||||
|
*poutbuf= av_malloc(buf_size - header_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
memcpy(*poutbuf, buf + header_size, buf_size - header_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
|
||||||
|
if(avctx->channels==2){
|
||||||
|
if((header & (3<<19)) != 3<<19){
|
||||||
|
(*poutbuf)[1] &= 0x3F;
|
||||||
|
(*poutbuf)[1] |= mode_extension<<6;
|
||||||
|
FFSWAP(int, (*poutbuf)[1], (*poutbuf)[2]);
|
||||||
|
}else{
|
||||||
|
(*poutbuf)[1] &= 0x8F;
|
||||||
|
(*poutbuf)[1] |= mode_extension<<4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVBitStreamFilter mp3_header_compress_bsf={
|
||||||
|
"mp3comp",
|
||||||
|
0,
|
||||||
|
mp3_header_compress,
|
||||||
|
};
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "mpegaudio.h"
|
||||||
|
#include "mpegaudiodata.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int mp3_header_decompress(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args,
|
||||||
|
uint8_t **poutbuf, int *poutbuf_size,
|
||||||
|
const uint8_t *buf, int buf_size, int keyframe){
|
||||||
|
uint32_t header;
|
||||||
|
int sample_rate= avctx->sample_rate;
|
||||||
|
int sample_rate_index=0;
|
||||||
|
int lsf, mpeg25, bitrate_index, frame_size;
|
||||||
|
|
||||||
|
header = AV_RB32(buf);
|
||||||
|
if(ff_mpa_check_header(header) >= 0){
|
||||||
|
*poutbuf= (uint8_t *) buf;
|
||||||
|
*poutbuf_size= buf_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(avctx->extradata_size != 15 || strcmp(avctx->extradata, "FFCMP3 0.0")){
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Extradata invalid %d\n", avctx->extradata_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
header= AV_RB32(avctx->extradata+11) & MP3_MASK;
|
||||||
|
|
||||||
|
lsf = sample_rate < (24000+32000)/2;
|
||||||
|
mpeg25 = sample_rate < (12000+16000)/2;
|
||||||
|
sample_rate_index= (header>>10)&3;
|
||||||
|
sample_rate= ff_mpa_freq_tab[sample_rate_index] >> (lsf + mpeg25); //in case sample rate is a little off
|
||||||
|
|
||||||
|
for(bitrate_index=2; bitrate_index<30; bitrate_index++){
|
||||||
|
frame_size = ff_mpa_bitrate_tab[lsf][2][bitrate_index>>1];
|
||||||
|
frame_size = (frame_size * 144000) / (sample_rate << lsf) + (bitrate_index&1);
|
||||||
|
if(frame_size == buf_size + 4)
|
||||||
|
break;
|
||||||
|
if(frame_size == buf_size + 6)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(bitrate_index == 30){
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Could not find bitrate_index.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
header |= (bitrate_index&1)<<9;
|
||||||
|
header |= (bitrate_index>>1)<<12;
|
||||||
|
header |= (frame_size == buf_size + 4)<<16; //FIXME actually set a correct crc instead of 0
|
||||||
|
|
||||||
|
*poutbuf_size= frame_size;
|
||||||
|
*poutbuf= av_malloc(frame_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
memcpy(*poutbuf + frame_size - buf_size, buf, buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||||
|
|
||||||
|
if(avctx->channels==2){
|
||||||
|
uint8_t *p= *poutbuf + frame_size - buf_size;
|
||||||
|
if(lsf){
|
||||||
|
FFSWAP(int, p[1], p[2]);
|
||||||
|
header |= (p[1] & 0xC0)>>2;
|
||||||
|
p[1] &= 0x3F;
|
||||||
|
}else{
|
||||||
|
header |= p[1] & 0x30;
|
||||||
|
p[1] &= 0xCF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AV_WB32(*poutbuf, header);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVBitStreamFilter mp3_header_decompress_bsf={
|
||||||
|
"mp3decomp",
|
||||||
|
0,
|
||||||
|
mp3_header_decompress,
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* MSMPEG4 backend for ffmpeg encoder and decoder
|
||||||
|
* copyright (c) 2007 Aurelien Jacobs <aurel@gnuage.org>
|
||||||
|
*
|
||||||
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg 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.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file msmpeg4.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FFMPEG_MSMPEG4_H
|
||||||
|
#define FFMPEG_MSMPEG4_H
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "avcodec.h"
|
||||||
|
#include "dsputil.h"
|
||||||
|
#include "mpegvideo.h"
|
||||||
|
|
||||||
|
#define INTER_INTRA_VLC_BITS 3
|
||||||
|
#define MB_NON_INTRA_VLC_BITS 9
|
||||||
|
#define MB_INTRA_VLC_BITS 9
|
||||||
|
|
||||||
|
extern VLC ff_mb_non_intra_vlc[4];
|
||||||
|
extern VLC ff_inter_intra_vlc;
|
||||||
|
|
||||||
|
void ff_msmpeg4_code012(PutBitContext *pb, int n);
|
||||||
|
void ff_msmpeg4_encode_block(MpegEncContext * s, DCTELEM * block, int n);
|
||||||
|
void ff_msmpeg4_handle_slices(MpegEncContext *s);
|
||||||
|
void ff_msmpeg4_encode_motion(MpegEncContext * s, int mx, int my);
|
||||||
|
int ff_msmpeg4_coded_block_pred(MpegEncContext * s, int n,
|
||||||
|
uint8_t **coded_block_ptr);
|
||||||
|
int ff_msmpeg4_decode_motion(MpegEncContext * s, int *mx_ptr, int *my_ptr);
|
||||||
|
int ff_msmpeg4_decode_block(MpegEncContext * s, DCTELEM * block,
|
||||||
|
int n, int coded, const uint8_t *scan_table);
|
||||||
|
int ff_wmv2_decode_mb(MpegEncContext *s, DCTELEM block[6][64]);
|
||||||
|
|
||||||
|
#define ENABLE_MSMPEG4_DECODER (ENABLE_MSMPEG4V1_DECODER || \
|
||||||
|
ENABLE_MSMPEG4V2_DECODER || \
|
||||||
|
ENABLE_MSMPEG4V3_DECODER || \
|
||||||
|
ENABLE_WMV2_DECODER)
|
||||||
|
#define ENABLE_MSMPEG4_ENCODER (ENABLE_MSMPEG4V1_ENCODER || \
|
||||||
|
ENABLE_MSMPEG4V2_ENCODER || \
|
||||||
|
ENABLE_MSMPEG4V3_ENCODER || \
|
||||||
|
ENABLE_WMV2_ENCODER)
|
||||||
|
#define ENABLE_MSMPEG4 (ENABLE_MSMPEG4_DECODER || ENABLE_MSMPEG4_ENCODER)
|
||||||
|
#define ENABLE_WMV2 (ENABLE_WMV2_DECODER || ENABLE_WMV2_ENCODER)
|
||||||
|
#define ENABLE_WMV_DECODER (ENABLE_WMV1_DECODER || ENABLE_WMV2_DECODER)
|
||||||
|
#define ENABLE_WMV_ENCODER (ENABLE_WMV1_ENCODER || ENABLE_WMV2_ENCODER)
|
||||||
|
|
||||||
|
#endif /* FFMPEG_MSMPEG4_H */
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,19 +2,21 @@
|
|||||||
* Micrsoft RLE Video Decoder
|
* Micrsoft RLE Video Decoder
|
||||||
* Copyright (C) 2003 the ffmpeg project
|
* Copyright (C) 2003 the ffmpeg project
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +36,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "avcodec.h"
|
#include "avcodec.h"
|
||||||
#include "dsputil.h"
|
#include "dsputil.h"
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ typedef struct MsrleContext {
|
|||||||
AVCodecContext *avctx;
|
AVCodecContext *avctx;
|
||||||
AVFrame frame;
|
AVFrame frame;
|
||||||
|
|
||||||
unsigned char *buf;
|
const unsigned char *buf;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
} MsrleContext;
|
} MsrleContext;
|
||||||
@@ -235,14 +236,13 @@ static void msrle_decode_pal8(MsrleContext *s)
|
|||||||
stream_ptr, s->size);
|
stream_ptr, s->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int msrle_decode_init(AVCodecContext *avctx)
|
static av_cold int msrle_decode_init(AVCodecContext *avctx)
|
||||||
{
|
{
|
||||||
MsrleContext *s = (MsrleContext *)avctx->priv_data;
|
MsrleContext *s = avctx->priv_data;
|
||||||
|
|
||||||
s->avctx = avctx;
|
s->avctx = avctx;
|
||||||
|
|
||||||
avctx->pix_fmt = PIX_FMT_PAL8;
|
avctx->pix_fmt = PIX_FMT_PAL8;
|
||||||
avctx->has_b_frames = 0;
|
|
||||||
s->frame.data[0] = NULL;
|
s->frame.data[0] = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -250,13 +250,9 @@ static int msrle_decode_init(AVCodecContext *avctx)
|
|||||||
|
|
||||||
static int msrle_decode_frame(AVCodecContext *avctx,
|
static int msrle_decode_frame(AVCodecContext *avctx,
|
||||||
void *data, int *data_size,
|
void *data, int *data_size,
|
||||||
uint8_t *buf, int buf_size)
|
const uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
MsrleContext *s = (MsrleContext *)avctx->priv_data;
|
MsrleContext *s = avctx->priv_data;
|
||||||
|
|
||||||
/* no supplementary picture */
|
|
||||||
if (buf_size == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
s->buf = buf;
|
s->buf = buf;
|
||||||
s->size = buf_size;
|
s->size = buf_size;
|
||||||
@@ -287,9 +283,9 @@ static int msrle_decode_frame(AVCodecContext *avctx,
|
|||||||
return buf_size;
|
return buf_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int msrle_decode_end(AVCodecContext *avctx)
|
static av_cold int msrle_decode_end(AVCodecContext *avctx)
|
||||||
{
|
{
|
||||||
MsrleContext *s = (MsrleContext *)avctx->priv_data;
|
MsrleContext *s = avctx->priv_data;
|
||||||
|
|
||||||
/* release the last frame */
|
/* release the last frame */
|
||||||
if (s->frame.data[0])
|
if (s->frame.data[0])
|
||||||
@@ -308,4 +304,5 @@ AVCodec msrle_decoder = {
|
|||||||
msrle_decode_end,
|
msrle_decode_end,
|
||||||
msrle_decode_frame,
|
msrle_decode_frame,
|
||||||
CODEC_CAP_DR1,
|
CODEC_CAP_DR1,
|
||||||
|
.long_name= NULL_IF_CONFIG_SMALL("Microsoft RLE"),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,20 +2,21 @@
|
|||||||
* Microsoft Video-1 Decoder
|
* Microsoft Video-1 Decoder
|
||||||
* Copyright (C) 2003 the ffmpeg project
|
* Copyright (C) 2003 the ffmpeg project
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This file is part of FFmpeg.
|
||||||
|
*
|
||||||
|
* FFmpeg is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
* version 2 of the License, or (at your option) any later version.
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This library is distributed in the hope that it will be useful,
|
* FFmpeg is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
* License along with FFmpeg; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,12 +35,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "avcodec.h"
|
#include "avcodec.h"
|
||||||
#include "dsputil.h"
|
|
||||||
|
|
||||||
#define PALETTE_COUNT 256
|
#define PALETTE_COUNT 256
|
||||||
#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])
|
|
||||||
#define CHECK_STREAM_PTR(n) \
|
#define CHECK_STREAM_PTR(n) \
|
||||||
if ((stream_ptr + n) > s->size ) { \
|
if ((stream_ptr + n) > s->size ) { \
|
||||||
av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \
|
av_log(s->avctx, AV_LOG_ERROR, " MS Video-1 warning: stream_ptr out of bounds (%d >= %d)\n", \
|
||||||
@@ -50,19 +48,18 @@
|
|||||||
typedef struct Msvideo1Context {
|
typedef struct Msvideo1Context {
|
||||||
|
|
||||||
AVCodecContext *avctx;
|
AVCodecContext *avctx;
|
||||||
DSPContext dsp;
|
|
||||||
AVFrame frame;
|
AVFrame frame;
|
||||||
|
|
||||||
unsigned char *buf;
|
const unsigned char *buf;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
int mode_8bit; /* if it's not 8-bit, it's 16-bit */
|
int mode_8bit; /* if it's not 8-bit, it's 16-bit */
|
||||||
|
|
||||||
} Msvideo1Context;
|
} Msvideo1Context;
|
||||||
|
|
||||||
static int msvideo1_decode_init(AVCodecContext *avctx)
|
static av_cold int msvideo1_decode_init(AVCodecContext *avctx)
|
||||||
{
|
{
|
||||||
Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data;
|
Msvideo1Context *s = avctx->priv_data;
|
||||||
|
|
||||||
s->avctx = avctx;
|
s->avctx = avctx;
|
||||||
|
|
||||||
@@ -75,9 +72,6 @@ static int msvideo1_decode_init(AVCodecContext *avctx)
|
|||||||
avctx->pix_fmt = PIX_FMT_RGB555;
|
avctx->pix_fmt = PIX_FMT_RGB555;
|
||||||
}
|
}
|
||||||
|
|
||||||
avctx->has_b_frames = 0;
|
|
||||||
dsputil_init(&s->dsp, avctx);
|
|
||||||
|
|
||||||
s->frame.data[0] = NULL;
|
s->frame.data[0] = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -244,25 +238,25 @@ static void msvideo1_decode_16bit(Msvideo1Context *s)
|
|||||||
flags = (byte_b << 8) | byte_a;
|
flags = (byte_b << 8) | byte_a;
|
||||||
|
|
||||||
CHECK_STREAM_PTR(4);
|
CHECK_STREAM_PTR(4);
|
||||||
colors[0] = LE_16(&s->buf[stream_ptr]);
|
colors[0] = AV_RL16(&s->buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
colors[1] = LE_16(&s->buf[stream_ptr]);
|
colors[1] = AV_RL16(&s->buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
|
|
||||||
if (colors[0] & 0x8000) {
|
if (colors[0] & 0x8000) {
|
||||||
/* 8-color encoding */
|
/* 8-color encoding */
|
||||||
CHECK_STREAM_PTR(12);
|
CHECK_STREAM_PTR(12);
|
||||||
colors[2] = LE_16(&s->buf[stream_ptr]);
|
colors[2] = AV_RL16(&s->buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
colors[3] = LE_16(&s->buf[stream_ptr]);
|
colors[3] = AV_RL16(&s->buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
colors[4] = LE_16(&s->buf[stream_ptr]);
|
colors[4] = AV_RL16(&s->buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
colors[5] = LE_16(&s->buf[stream_ptr]);
|
colors[5] = AV_RL16(&s->buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
colors[6] = LE_16(&s->buf[stream_ptr]);
|
colors[6] = AV_RL16(&s->buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
colors[7] = LE_16(&s->buf[stream_ptr]);
|
colors[7] = AV_RL16(&s->buf[stream_ptr]);
|
||||||
stream_ptr += 2;
|
stream_ptr += 2;
|
||||||
|
|
||||||
for (pixel_y = 0; pixel_y < 4; pixel_y++) {
|
for (pixel_y = 0; pixel_y < 4; pixel_y++) {
|
||||||
@@ -299,13 +293,9 @@ static void msvideo1_decode_16bit(Msvideo1Context *s)
|
|||||||
|
|
||||||
static int msvideo1_decode_frame(AVCodecContext *avctx,
|
static int msvideo1_decode_frame(AVCodecContext *avctx,
|
||||||
void *data, int *data_size,
|
void *data, int *data_size,
|
||||||
uint8_t *buf, int buf_size)
|
const uint8_t *buf, int buf_size)
|
||||||
{
|
{
|
||||||
Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data;
|
Msvideo1Context *s = avctx->priv_data;
|
||||||
|
|
||||||
/* no supplementary picture */
|
|
||||||
if (buf_size == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
s->buf = buf;
|
s->buf = buf;
|
||||||
s->size = buf_size;
|
s->size = buf_size;
|
||||||
@@ -329,9 +319,9 @@ static int msvideo1_decode_frame(AVCodecContext *avctx,
|
|||||||
return buf_size;
|
return buf_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int msvideo1_decode_end(AVCodecContext *avctx)
|
static av_cold int msvideo1_decode_end(AVCodecContext *avctx)
|
||||||
{
|
{
|
||||||
Msvideo1Context *s = (Msvideo1Context *)avctx->priv_data;
|
Msvideo1Context *s = avctx->priv_data;
|
||||||
|
|
||||||
if (s->frame.data[0])
|
if (s->frame.data[0])
|
||||||
avctx->release_buffer(avctx, &s->frame);
|
avctx->release_buffer(avctx, &s->frame);
|
||||||
@@ -349,4 +339,5 @@ AVCodec msvideo1_decoder = {
|
|||||||
msvideo1_decode_end,
|
msvideo1_decode_end,
|
||||||
msvideo1_decode_frame,
|
msvideo1_decode_frame,
|
||||||
CODEC_CAP_DR1,
|
CODEC_CAP_DR1,
|
||||||
|
.long_name= NULL_IF_CONFIG_SMALL("Microsoft Video 1"),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user